aboutsummaryrefslogtreecommitdiff
path: root/externals/grill/py
diff options
context:
space:
mode:
authorThomas Grill <xovo@users.sourceforge.net>2005-07-09 13:03:34 +0000
committerThomas Grill <xovo@users.sourceforge.net>2005-07-09 13:03:34 +0000
commit29416a643b9c3d19a60b91b37a263d300c11486b (patch)
treedd28d4b6c6a6e4229de8c5e8ae76f4686df935c6 /externals/grill/py
parent897b80c5585f7c9031ff1aafb504c21a9d3b1606 (diff)
python-like dotted module.function syntax
reworked outbound message generation (now with symbols instead of one-element anythings) multiply inlets for py (hot and cold inlets) cleaned up float vs. int pyext tags pymeth object for object methods enable built-in functions sequence protocol for symbol type enabled built-in functions py: allow all callables svn path=/trunk/; revision=3310
Diffstat (limited to 'externals/grill/py')
-rw-r--r--externals/grill/py/package.txt2
-rw-r--r--externals/grill/py/pd/builtins-1.pd47
-rw-r--r--externals/grill/py/pd/methods-1.pd24
-rw-r--r--externals/grill/py/pd/methods-2.pd28
-rw-r--r--externals/grill/py/pd/script-1.pd26
-rw-r--r--externals/grill/py/pd/simple-2.pd8
-rw-r--r--externals/grill/py/py.vcproj7
-rw-r--r--externals/grill/py/readme.txt5
-rw-r--r--externals/grill/py/source/clmeth.cpp7
-rw-r--r--externals/grill/py/source/modmeth.cpp10
-rw-r--r--externals/grill/py/source/py.cpp137
-rw-r--r--externals/grill/py/source/pyargs.cpp40
-rw-r--r--externals/grill/py/source/pybase.cpp52
-rw-r--r--externals/grill/py/source/pybase.h7
-rw-r--r--externals/grill/py/source/pyext.cpp9
-rw-r--r--externals/grill/py/source/pymeth.cpp449
-rw-r--r--externals/grill/py/source/pysymbol.cpp87
17 files changed, 819 insertions, 126 deletions
diff --git a/externals/grill/py/package.txt b/externals/grill/py/package.txt
index 31637831..5204b0a8 100644
--- a/externals/grill/py/package.txt
+++ b/externals/grill/py/package.txt
@@ -11,6 +11,6 @@ SRCS= \
py.cpp pyext.cpp modmeth.cpp clmeth.cpp \
register.cpp bound.cpp pyargs.cpp \
pysymbol.cpp pybuffer.cpp pydsp.cpp \
- pyatom.cpp pybase.cpp
+ pyatom.cpp pybase.cpp pymeth.cpp
HDRS= pyprefix.h main.h pyext.h pysymbol.h pybuffer.h pyatom.h pybase.h
diff --git a/externals/grill/py/pd/builtins-1.pd b/externals/grill/py/pd/builtins-1.pd
new file mode 100644
index 00000000..095e7690
--- /dev/null
+++ b/externals/grill/py/pd/builtins-1.pd
@@ -0,0 +1,47 @@
+#N canvas 327 349 706 421 12;
+#X obj 36 241 py .range @xlate 0;
+#X floatatom 35 356 5 0 0 0 - - -;
+#X obj 35 323 py .sum;
+#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 obj 36 159 nbx 5 14 -1e+037 1e+037 0 1 empty empty min 0 -6 0 10
+-262131 -1 -1 38 256;
+#X obj 95 159 nbx 5 14 -1e+037 1e+037 0 1 empty empty max 0 -6 0 10
+-262131 -1 -1 100 256;
+#X obj 154 159 nbx 5 14 1 100000 1 1 empty empty step 0 -6 0 10 -262131
+-1 -1 1 256;
+#N canvas 0 0 462 312 pak3 0;
+#X obj 34 26 inlet;
+#X obj 81 28 inlet;
+#X obj 129 28 inlet;
+#X obj 36 158 outlet;
+#X obj 36 123 pack 0 0 0;
+#X obj 61 78 t b f;
+#X obj 108 80 t b f;
+#X obj 208 46 loadbang;
+#X obj 208 73 1;
+#X connect 0 0 4 0;
+#X connect 1 0 5 0;
+#X connect 2 0 6 0;
+#X connect 4 0 3 0;
+#X connect 5 0 4 0;
+#X connect 5 1 4 1;
+#X connect 6 0 4 0;
+#X connect 6 1 4 2;
+#X connect 7 0 8 0;
+#X connect 8 0 4 2;
+#X restore 36 195 pd pak3;
+#X text 115 240 construct a Python list;
+#X text 78 282 Python object pointer is propagated to next object;
+#X text 106 320 calculate sum over list elements;
+#X text 21 73 Py can use built-in Python functions;
+#X text 21 97 A . preceding the function name searches for the function
+in either the pyext module or in __builtins__;
+#X connect 0 0 2 1;
+#X connect 2 0 1 0;
+#X connect 6 0 9 0;
+#X connect 7 0 9 1;
+#X connect 8 0 9 2;
+#X connect 9 0 0 1;
diff --git a/externals/grill/py/pd/methods-1.pd b/externals/grill/py/pd/methods-1.pd
new file mode 100644
index 00000000..8d49f319
--- /dev/null
+++ b/externals/grill/py/pd/methods-1.pd
@@ -0,0 +1,24 @@
+#N canvas 540 469 714 349 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 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;
diff --git a/externals/grill/py/pd/methods-2.pd b/externals/grill/py/pd/methods-2.pd
new file mode 100644
index 00000000..b10e183c
--- /dev/null
+++ b/externals/grill/py/pd/methods-2.pd
@@ -0,0 +1,28 @@
+#N canvas 540 469 734 339 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 - #0-t -;
+#X text 23 119 enter some text;
+#X text 21 73 Py can act on Python objects in a object-oriented manner
+;
+#X obj 25 252 pym 2 *;
+#X obj 213 169 t b f;
+#X text 105 251 repeat text;
+#X text 215 117 multiply it!;
+#X symbolatom 25 283 80 0 0 0 - - -;
+#X obj 214 139 nbx 5 14 1 100 0 1 empty empty empty 0 -6 0 10 -262131
+-1 -1 34 256;
+#N canvas 0 0 458 308 init 0;
+#X obj 61 116 s \$0-t;
+#X obj 64 44 loadbang;
+#X obj 64 81 symbol a;
+#X connect 1 0 2 0;
+#X connect 2 0 0 0;
+#X restore 606 127 pd init;
+#X connect 3 0 6 1;
+#X connect 6 0 10 0;
+#X connect 7 0 6 0;
+#X connect 7 1 6 2;
+#X connect 11 0 7 0;
diff --git a/externals/grill/py/pd/script-1.pd b/externals/grill/py/pd/script-1.pd
index 328b096d..98fee527 100644
--- a/externals/grill/py/pd/script-1.pd
+++ b/externals/grill/py/pd/script-1.pd
@@ -1,4 +1,4 @@
-#N canvas 297 17 696 538 12;
+#N canvas 297 17 700 542 12;
#X obj 39 278 print;
#X obj 345 251 print;
#X msg 499 149 freakhole;
@@ -26,7 +26,6 @@ file.;
#X obj 39 241 py script strcat;
#X obj 43 424 py script addall;
#X obj 350 420 py script;
-#X obj 516 419 py script ret3;
#X obj 346 204 py script strlen;
#X msg 21 159 dir;
#X obj 146 279 print A;
@@ -39,26 +38,27 @@ file.;
#X text 556 181 too many args;
#X text 505 372 just trigger without arguments;
#X msg 386 371 set ret4;
-#X connect 2 0 25 1;
+#X obj 516 419 py script ret3;
+#X connect 2 0 24 1;
#X connect 3 0 21 1;
#X connect 4 0 21 1;
#X connect 6 0 22 1;
#X connect 7 0 22 1;
#X connect 9 0 23 0;
-#X connect 11 0 24 0;
+#X connect 11 0 35 0;
#X connect 12 0 21 1;
-#X connect 13 0 25 0;
+#X connect 13 0 24 0;
#X connect 14 0 23 0;
#X connect 15 0 23 0;
-#X connect 17 0 25 1;
+#X connect 17 0 24 1;
#X connect 19 0 21 0;
#X connect 21 0 0 0;
-#X connect 21 1 27 0;
+#X connect 21 1 26 0;
#X connect 22 0 5 0;
#X connect 23 0 8 0;
-#X connect 24 0 10 0;
-#X connect 25 0 1 0;
-#X connect 26 0 21 0;
-#X connect 28 0 21 0;
-#X connect 32 0 25 1;
-#X connect 35 0 23 0;
+#X connect 24 0 1 0;
+#X connect 25 0 21 0;
+#X connect 27 0 21 0;
+#X connect 31 0 24 1;
+#X connect 34 0 23 0;
+#X connect 35 0 10 0;
diff --git a/externals/grill/py/pd/simple-2.pd b/externals/grill/py/pd/simple-2.pd
index 1845b032..4c857d49 100644
--- a/externals/grill/py/pd/simple-2.pd
+++ b/externals/grill/py/pd/simple-2.pd
@@ -1,4 +1,4 @@
-#N canvas 95 223 654 394 12;
+#N canvas 570 275 788 398 12;
#X floatatom 202 113 5 0 0 0 - - -;
#X text 338 286 watch the console output!;
#X msg 20 115 help;
@@ -16,13 +16,11 @@ file.;
#X msg 120 174 hello;
#X msg 193 180 hello;
#X msg 266 179 msg;
-#X msg 325 154 hello 3;
-#X text 338 189 special case: 'hello' handler doesn't like args \,
-so _anything_ is called!;
#X obj 16 13 cnv 15 600 40 empty empty py/pyext 10 22 0 24 -260818
-1 0;
#X text 213 16 Python script objects \, (C)2003-2005 Thomas Grill;
#X text 213 32 http://grrrr.org/ext;
+#X msg 333 186 whoopie a b c;
#X connect 0 0 8 1;
#X connect 2 0 8 0;
#X connect 4 0 8 0;
@@ -36,4 +34,4 @@ so _anything_ is called!;
#X connect 13 0 8 1;
#X connect 14 0 8 3;
#X connect 15 0 8 2;
-#X connect 16 0 8 3;
+#X connect 19 0 8 3;
diff --git a/externals/grill/py/py.vcproj b/externals/grill/py/py.vcproj
index a103c872..31e24d3c 100644
--- a/externals/grill/py/py.vcproj
+++ b/externals/grill/py/py.vcproj
@@ -1244,6 +1244,13 @@
</FileConfiguration>
</File>
</Filter>
+ <Filter
+ Name="meth"
+ Filter="">
+ <File
+ RelativePath=".\source\pymeth.cpp">
+ </File>
+ </Filter>
<File
RelativePath="source\main.cpp">
<FileConfiguration
diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt
index 309e99d5..c36a081b 100644
--- a/externals/grill/py/readme.txt
+++ b/externals/grill/py/readme.txt
@@ -91,6 +91,11 @@ Version history:
- ADD: py can have multiple inlets for multiple function arguments (right inlets are non-triggering)
- ADD: allow module.function syntax for py and pyext
- FIX: pyext: cleanup up float vs. int ... first decision is made by tag, afterwards a conversion is tried
+- ADD: pym: object-oriented object... Python methods for any object type
+- ADD: py: allow all callables (also object constructors and builtins)
+- 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)
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 303b5888..37ba257e 100644
--- a/externals/grill/py/source/clmeth.cpp
+++ b/externals/grill/py/source/clmeth.cpp
@@ -182,7 +182,7 @@ PyObject *pyext::pyext_outlet(PyObject *,PyObject *args)
// offset outlet by signal outlets
o += ext->sigoutlets;
- if(ext->OutObject(ext,o,val))
+ if(ext->OutObject(ext,o-1,val))
ok = true;
else
PyErr_SetString(PyExc_ValueError,"pyext - _outlet: invalid arguments");
@@ -295,11 +295,12 @@ PyObject *pyext::pyext_tocanvas(PyObject *,PyObject *args)
val = PyTuple_GetSlice(args,1,sz); // new ref
flext::AtomListStatic<16> lst;
- if(GetPyArgs(lst,val)) {
+ const t_symbol *sym = GetPyArgs(lst,val);
+ if(sym) {
t_glist *gl = ext->thisCanvas(); //canvas_getcurrent();
t_class **cl = (t_pd *)gl;
if(cl)
- pd_forwardmess(cl,lst.Count(),lst.Atoms());
+ pd_forwardmess(cl,lst.Count(),lst.Atoms());
#ifdef FLEXT_DEBUG
else
post("pyext - no parent canvas?!");
diff --git a/externals/grill/py/source/modmeth.cpp b/externals/grill/py/source/modmeth.cpp
index d56441ac..44299b0c 100644
--- a/externals/grill/py/source/modmeth.cpp
+++ b/externals/grill/py/source/modmeth.cpp
@@ -128,13 +128,9 @@ PyObject *pybase::py_send(PyObject *,PyObject *args)
val = PySequence_GetSlice(args,1,sz); // new ref
AtomListStatic<16> lst;
- if(GetPyArgs(lst,val)) {
- bool ok;
- if(lst.Count() && IsSymbol(lst[0]))
- ok = Forward(recv,GetSymbol(lst[0]),lst.Count()-1,lst.Atoms()+1);
- else
- ok = Forward(recv,lst);
-
+ const t_symbol *sym = GetPyArgs(lst,val);
+ if(sym) {
+ bool ok = Forward(recv,sym,lst.Count(),lst.Atoms());
#ifdef FLEXT_DEBUG
if(!ok)
post("py/pyext - Receiver doesn't exist");
diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp
index d007f0c3..7cb7fa97 100644
--- a/externals/grill/py/source/py.cpp
+++ b/externals/grill/py/source/py.cpp
@@ -44,7 +44,7 @@ protected:
virtual void Load();
virtual void Unload();
- bool SetFunction(const char *func);
+ bool SetFunction(const t_symbol *func);
bool ResetFunction();
virtual bool thrcall(void *data);
@@ -122,11 +122,15 @@ pyobj::pyobj(int argc,const t_atom *argv)
PyThreadState *state = PyLockSys();
- int inlets = -1; // -1 signals non-explicit definition
+ int inlets;
if(argc && CanbeInt(*argv)) {
inlets = GetAInt(*argv);
+ if(inlets < 1) inlets = 1;
argv++,argc--;
}
+ else
+ // -1 signals non-explicit definition
+ inlets = -1;
if(inlets >= 1) {
objects = new PyObject *[inlets];
@@ -136,7 +140,7 @@ pyobj::pyobj(int argc,const t_atom *argv)
AddInAnything(1+(inlets < 0?1:inlets));
AddOutAnything();
- const char *funnm = NULL;
+ const t_symbol *funnm = NULL;
// init script module
if(argc) {
@@ -151,15 +155,24 @@ pyobj::pyobj(int argc,const t_atom *argv)
char *pt = strrchr(modnm,'.'); // search for last dot
if(pt && *pt) {
- funnm = pt+1;
+ funnm = MakeSymbol(pt+1);
*pt = 0;
- }
- char dir[1024];
- GetModulePath(modnm,dir,sizeof(dir));
- AddToPath(dir);
+#if 0
+ if(!*modnm)
+ // if module name is empty set it to __builtin__
+ strcpy(modnm,"__builtin__");
+#endif
+ }
- ImportModule(modnm);
+ if(*modnm) {
+ char dir[1024];
+ GetModulePath(modnm,dir,sizeof(dir));
+ AddToPath(dir);
+ ImportModule(modnm);
+ }
+ else
+ ImportModule(NULL);
}
else
PyErr_SetString(PyExc_ValueError,"Invalid module name");
@@ -169,7 +182,7 @@ pyobj::pyobj(int argc,const t_atom *argv)
if(funnm || argc) {
if(!funnm) {
- funnm = GetAString(*argv);
+ funnm = GetASymbol(*argv);
argv++,argc--;
}
@@ -225,7 +238,7 @@ void pyobj::m_set(int argc,const t_atom *argv)
}
if(argc) {
- const char *fn = GetAString(*argv);
+ const t_symbol *fn = GetASymbol(*argv);
if(fn)
SetFunction(fn);
else
@@ -269,18 +282,24 @@ void pyobj::m_help()
bool pyobj::ResetFunction()
{
+ // function was borrowed from dict!
function = NULL;
- if(!module || !dict)
- post("%s - No module loaded",thisName());
+ if(!dict)
+ post("%s - No namespace available",thisName());
else {
if(funname) {
function = PyDict_GetItemString(dict,(char *)GetString(funname)); // borrowed!!!
+
+ if(!function && dict == module_dict)
+ // search also in __builtins__
+ function = PyDict_GetItemString(builtins_dict,(char *)GetString(funname)); // borrowed!!!
+
if(!function)
PyErr_SetString(PyExc_AttributeError,"Function not found");
- else if(!PyFunction_Check(function)) {
+ else if(!PyCallable_Check(function)) {
function = NULL;
- PyErr_SetString(PyExc_TypeError,"Attribute is not a function");
+ PyErr_SetString(PyExc_TypeError,"Attribute is not callable");
}
}
}
@@ -289,10 +308,10 @@ bool pyobj::ResetFunction()
return function != NULL;
}
-bool pyobj::SetFunction(const char *func)
+bool pyobj::SetFunction(const t_symbol *func)
{
if(func) {
- funname = MakeSymbol(func);
+ funname = func;
withfunction = ResetFunction();
}
else {
@@ -307,7 +326,7 @@ bool pyobj::SetFunction(const char *func)
void pyobj::LoadModule()
{
- SetFunction(funname?GetString(funname):NULL);
+ SetFunction(funname);
}
void pyobj::UnloadModule()
@@ -342,68 +361,68 @@ bool pyobj::callpy(PyObject *fun,PyObject *args)
bool pyobj::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 = PyLock();
+
bool ret = false;
- if(n == 0 && s != sym_bang) goto end;
-
if(objects && 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
- goto end;
- }
+ if(n > 1) ret = true; // just store, don't trigger
}
- PyThreadState *state = PyLock();
-
- if(withfunction) {
- if(function) {
- Py_INCREF(function);
-
- PyObject *pargs;
-
- if(objects) {
- int inlets = CntIn()-1;
- pargs = PyTuple_New(inlets);
- for(int i = 0; i < inlets; ++i) {
- Py_INCREF(objects[i]);
- PyTuple_SET_ITEM(pargs,i,objects[i]);
+ if(!ret) {
+ if(withfunction) {
+ if(function) {
+ Py_INCREF(function);
+
+ PyObject *pargs;
+
+ if(objects) {
+ int inlets = CntIn()-1;
+ pargs = PyTuple_New(inlets);
+ for(int i = 0; i < inlets; ++i) {
+ Py_INCREF(objects[i]);
+ PyTuple_SET_ITEM(pargs,i,objects[i]);
+ }
}
- }
- else
- // construct tuple from args
- pargs = MakePyArgs(s,argc,argv);
+ else
+ // construct tuple from args
+ // if n == 0, it's a pure bang
+ pargs = MakePyArgs(n?s:NULL,argc,argv);
- ret = gencall(function,pargs); // references are stolen
+ ret = gencall(function,pargs); // references are stolen
+ }
+ else
+ PyErr_SetString(PyExc_RuntimeError,"No function set");
}
- else
- PyErr_SetString(PyExc_RuntimeError,"No function set");
- }
- else if(module) {
- // no function defined as creation argument -> use message tag
- if(s) {
- PyObject *func = PyObject_GetAttrString(module,const_cast<char *>(GetString(s)));
- if(func) {
- PyObject *pargs = MakePyArgs(sym_list,argc,argv);
- ret = gencall(func,pargs);
+ else if(module) {
+ // no function defined as creation argument -> use message tag
+ if(s) {
+ PyObject *func = PyObject_GetAttrString(module,const_cast<char *>(GetString(s)));
+ if(func) {
+ PyObject *pargs = MakePyArgs(sym_list,argc,argv);
+ ret = gencall(func,pargs);
+ }
}
+ else
+ PyErr_SetString(PyExc_RuntimeError,"No function set");
}
- else
- PyErr_SetString(PyExc_RuntimeError,"No function set");
- }
- Report();
+ Report();
+ }
PyUnlock(state);
Respond(ret);
-end:
- return ret || flext_base::CbMethodResort(n,s,argc,argv);
+ return ret;
}
void pyobj::CbClick() { pybase::OpenEditor(); }
diff --git a/externals/grill/py/source/pyargs.cpp b/externals/grill/py/source/pyargs.cpp
index f08369a7..5c903f17 100644
--- a/externals/grill/py/source/pyargs.cpp
+++ b/externals/grill/py/source/pyargs.cpp
@@ -17,19 +17,19 @@ static PyObject *MakePyAtom(const t_atom &at)
{
if(flext::IsSymbol(at))
return pySymbol_FromSymbol(flext::GetSymbol(at));
-/*
+#if 1
else if(flext::CanbeInt(at) || flext::CanbeFloat(at)) {
// if a number can be an integer... let it be an integer!
int ival = flext::GetAInt(at);
double fval = flext::GetAFloat(at);
return (double)ival == fval?PyInt_FromLong(ival):PyFloat_FromDouble(fval);
}
-*/
+#else
else if(flext::IsFloat(at))
return PyFloat_FromDouble(flext::GetFloat(at));
else if(flext::IsInt(at))
return PyInt_FromLong(flext::GetInt(at));
-
+#endif
return NULL;
}
@@ -99,7 +99,8 @@ PyObject *pybase::MakePyArg(const t_symbol *s,int argc,const t_atom *argv)
if(s == symatom && (ret = MakePyAtom(argc,argv)) != NULL) {
// ok!
}
- else if(argc == 1 && IsAtom(s))
+ else if(argc == 1 && !IsAnything(s))
+ // convert atoms and one-element lists
ret = MakePyAtom(*argv);
else {
bool any = s != sym_list;
@@ -125,14 +126,13 @@ PyObject *pybase::MakePyArg(const t_symbol *s,int argc,const t_atom *argv)
return ret;
}
-bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs)
+const t_symbol *pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs)
{
if(pValue == NULL) return false;
// analyze return value or tuple
int rargc = 0;
- bool ok = true;
retval tp = nothing;
if(PyString_Check(pValue)) {
@@ -152,6 +152,8 @@ bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs)
lst(offs+rargc);
+ const t_symbol *sym = NULL;
+
for(int ix = 0; ix < rargc; ++ix) {
PyObject *arg;
if(tp == sequ)
@@ -160,11 +162,11 @@ bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs)
arg = pValue;
t_atom &at = lst[offs+ix];
- if(PyInt_Check(arg)) SetInt(at,PyInt_AsLong(arg));
- else if(PyLong_Check(arg)) SetInt(at,PyLong_AsLong(arg));
- else if(PyFloat_Check(arg)) SetFloat(at,(float)PyFloat_AsDouble(arg));
- else if(pySymbol_Check(arg)) SetSymbol(at,pySymbol_AS_SYMBOL(arg));
- else if(PyString_Check(arg)) SetString(at,PyString_AS_STRING(arg));
+ 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_ !!!
@@ -180,25 +182,27 @@ bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs)
post("py/pyext: Could not convert argument %s",tmp);
Py_XDECREF(stp);
Py_XDECREF(tp);
- ok = false;
+
+ SetSymbol(at,sym__); sym = sym_symbol;
}
if(tp == sequ)
Py_DECREF(arg);
}
- return ok;
+ if(sym && tp == sequ) sym = sym_list;
+
+ return sym;
}
-bool pybase::GetPyAtom(AtomList &lst,PyObject *obj)
+const t_symbol *pybase::GetPyAtom(AtomList &lst,PyObject *obj)
{
size_t atom = PyAtom::Register(obj);
size_t szat = sizeof(atom)/2;
- lst(1+szat);
- SetSymbol(lst[0],symatom);
+ lst(szat);
for(size_t i = 0; i < szat; ++i,atom >>= 16)
- flext::SetInt(lst[i+1],(int)(atom&((1<<16)-1)));
- return true;
+ flext::SetInt(lst[i],(int)(atom&((1<<16)-1)));
+ return symatom;
}
diff --git a/externals/grill/py/source/pybase.cpp b/externals/grill/py/source/pybase.cpp
index cc51a59e..3bc589de 100644
--- a/externals/grill/py/source/pybase.cpp
+++ b/externals/grill/py/source/pybase.cpp
@@ -62,6 +62,10 @@ void pybase::FreeThreadState()
PyObject *pybase::module_obj = NULL;
PyObject *pybase::module_dict = NULL;
+PyObject *pybase::builtins_obj = NULL;
+PyObject *pybase::builtins_dict = NULL;
+
+const t_symbol *pybase::sym_fint = NULL;
// -----------------------------------------------------------------------------------------------------------
@@ -128,6 +132,9 @@ void pybase::lib_setup()
Py_DECREF(gcobj);
}
+ builtins_obj = PyImport_ImportModule("__builtin__");
+ builtins_dict = PyModule_GetDict(builtins_obj); // borrowed reference
+
// add symbol type
initsymbol();
PyModule_AddObject(module_obj,"Symbol",(PyObject *)&pySymbol_Type);
@@ -144,9 +151,16 @@ void pybase::lib_setup()
initsamplebuffer();
PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type);
+#if FLEXT_SYS == FLEXT_SYS_PD
+ sym_fint = sym_float;
+#else
+ sym_fint = sym_int;
+#endif
+
// -------------------------------------------------------------
FLEXT_SETUP(pyobj);
+ FLEXT_SETUP(pymeth);
FLEXT_SETUP(pyext);
FLEXT_DSP_SETUP(pydsp);
@@ -213,8 +227,11 @@ void pybase::GetDir(PyObject *obj,AtomList &lst)
if(!pvar)
PyErr_Print(); // no method found
else {
- if(!GetPyArgs(lst,pvar))
+ const t_symbol *sym = GetPyArgs(lst,pvar);
+ if(!sym)
post("py/pyext - Argument list could not be created");
+ else
+ FLEXT_ASSERT(sym == sym_list);
Py_DECREF(pvar);
}
@@ -294,9 +311,12 @@ void pybase::SetArgs()
bool pybase::ImportModule(const char *name)
{
- if(!name) return false;
- if(modname == name) return true;
- modname = name;
+ if(name) {
+ if(modname == name) return true;
+ modname = name;
+ }
+ else
+ modname.clear();
return ReloadModule();
}
@@ -321,9 +341,17 @@ bool pybase::ReloadModule()
bool ok = false;
SetArgs();
- PyObject *newmod = module
- ?PyImport_ReloadModule(module)
- :PyImport_ImportModule((char *)modname.c_str());
+ PyObject *newmod;
+
+ if(modname.length())
+ newmod = module
+ ?PyImport_ReloadModule(module)
+ :PyImport_ImportModule((char *)modname.c_str());
+ else {
+ // if no module name given, take py module
+ newmod = module_obj;
+ Py_INCREF(newmod);
+ }
if(!newmod) {
// unload faulty module
@@ -415,15 +443,11 @@ void pybase::AddCurrentPath(t_canvas *cnv)
bool pybase::OutObject(flext_base *ext,int o,PyObject *obj)
{
flext::AtomListStatic<16> lst;
- if(xlate?GetPyArgs(lst,obj):GetPyAtom(lst,obj)) {
+ const t_symbol *sym = xlate?GetPyArgs(lst,obj):GetPyAtom(lst,obj);
+ if(sym) {
// call to outlet _outside_ the Mutex lock!
// otherwise (if not detached) deadlock will occur
- if(lst.Count() && IsSymbol(lst[0]))
- ext->ToOutAnything(o,GetSymbol(lst[0]),lst.Count()-1,lst.Atoms()+1);
- else if(lst.Count() > 1)
- ext->ToOutList(o,lst);
- else
- ext->ToOutAtom(o,lst[0]);
+ ext->ToOutAnything(o,sym,lst.Count(),lst.Atoms());
return true;
}
else
diff --git a/externals/grill/py/source/pybase.h b/externals/grill/py/source/pybase.h
index ea5f6b49..068aeb86 100644
--- a/externals/grill/py/source/pybase.h
+++ b/externals/grill/py/source/pybase.h
@@ -26,8 +26,8 @@ public:
static PyObject *MakePyArgs(const t_symbol *s,int argc,const t_atom *argv,int inlet = -1);
static PyObject *MakePyArg(const t_symbol *s,int argc,const t_atom *argv);
- static bool GetPyArgs(AtomList &lst,PyObject *pValue,int offs = 0);
- static bool GetPyAtom(AtomList &lst,PyObject *pValue);
+ static const t_symbol *GetPyArgs(AtomList &lst,PyObject *pValue,int offs = 0);
+ static const t_symbol *GetPyAtom(AtomList &lst,PyObject *pValue);
static void lib_setup();
@@ -94,6 +94,7 @@ protected:
// --- module stuff -----
static PyObject *module_obj,*module_dict;
+ static PyObject *builtins_obj,*builtins_dict;
static PyMethodDef func_tbl[];
static PyObject *py__doc__(PyObject *,PyObject *args);
@@ -161,6 +162,8 @@ protected:
static PyThreadState *FindThreadState() { return NULL; }
#endif
+ static const t_symbol *sym_fint; // float or int symbol, depending on native number message type
+
public:
#ifdef FLEXT_THREADS
diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp
index 88b5de0c..593c8bd1 100644
--- a/externals/grill/py/source/pyext.cpp
+++ b/externals/grill/py/source/pyext.cpp
@@ -420,7 +420,9 @@ void pyext::m_get(const t_symbol *s)
PyObject *pvar = PyObject_GetAttrString(pyobj,const_cast<char *>(GetString(s))); /* fetch bound method */
if(pvar) {
flext::AtomListStatic<16> lst;
- if(GetPyArgs(lst,pvar,1)) {
+ const t_symbol *sym = GetPyArgs(lst,pvar,1);
+ if(sym) {
+ FLEXT_ASSERT(!IsAnything(sym));
// dump value to attribute outlet
SetSymbol(lst[0],s);
ToOutAnything(GetOutAttr(),sym_get,lst.Count(),lst.Atoms());
@@ -469,7 +471,10 @@ void pyext::m_set(int argc,const t_atom *argv)
bool pyext::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv)
{
- return (pyobj && n >= 1 && work(n,s,argc,argv)) || flext_dsp::CbMethodResort(n,s,argc,argv);
+ if(!n)
+ return flext_dsp::CbMethodResort(n,s,argc,argv);
+
+ return pyobj && work(n,s,argc,argv);
}
diff --git a/externals/grill/py/source/pymeth.cpp b/externals/grill/py/source/pymeth.cpp
new file mode 100644
index 00000000..8c80bd43
--- /dev/null
+++ b/externals/grill/py/source/pymeth.cpp
@@ -0,0 +1,449 @@
+/*
+
+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 <map>
+
+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<const t_symbol *,const t_symbol *> 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);
+ virtual void CbClick();
+
+ 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 bool thrcall(void *data);
+ virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv);
+
+ PyObject **objects;
+
+private:
+
+ virtual bool 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(xlate)
+ 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)
+ FLEXT_THREAD(threadworker)
+ FLEXT_THREAD_X(work_wrapper)
+#else
+ FLEXT_CALLBACK_X(work_wrapper)
+#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,"xlate",xlate);
+ 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);
+ // launch thread worker
+ FLEXT_CALLMETHOD(threadworker);
+#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);
+}
+
+bool 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();
+ Py_DECREF(ret);
+ return true;
+ }
+}
+
+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 = PyLock();
+
+ 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]);
+ }
+
+ ret = gencall(function,pargs); // references are stolen
+ }
+ else
+ PyErr_SetString(PyExc_RuntimeError,"No function set");
+
+ Report();
+ }
+
+ PyUnlock(state);
+
+ Respond(ret);
+
+ return ret;
+}
+
+void pymeth::CbClick() { pybase::OpenEditor(); }
+
+void pymeth::DumpOut(const t_symbol *sym,int argc,const t_atom *argv)
+{
+ ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv);
+}
+
+bool pymeth::thrcall(void *data)
+{
+ return FLEXT_CALLMETHOD_X(work_wrapper,data);
+}
diff --git a/externals/grill/py/source/pysymbol.cpp b/externals/grill/py/source/pysymbol.cpp
index 189d6a6f..be7d3139 100644
--- a/externals/grill/py/source/pysymbol.cpp
+++ b/externals/grill/py/source/pysymbol.cpp
@@ -81,6 +81,89 @@ static long symbol_hash(PyObject *self)
return (long)pySymbol_AS_SYMBOL(self);
}
+
+static int symbol_length(pySymbol *self)
+{
+ return strlen(flext::GetString(self->sym));
+}
+
+static PyObject *symbol_item(pySymbol *self, int i)
+{
+ const char *str = flext::GetString(self->sym);
+ int len = strlen(str);
+ if(i < 0) i += len;
+
+ if(i >= 0 && i < len)
+ return PyString_FromStringAndSize(str+i,1);
+ else {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+}
+
+static PyObject *symbol_slice(pySymbol *self,int ilow = 0,int ihigh = 1<<(sizeof(int)*8-2))
+{
+ const char *str = flext::GetString(self->sym);
+ int len = strlen(str);
+ if(ilow < 0) {
+ ilow += len;
+ if(ilow < 0) ilow = 0;
+ }
+ if(ihigh < 0) ihigh += len;
+ if(ihigh >= len) ihigh = len-1;
+
+ return PyString_FromStringAndSize(str+ilow,ilow <= ihigh?ihigh-ilow+1:0);
+}
+
+static PyObject *symbol_concat(pySymbol *self,PyObject *op)
+{
+ PyObject *nobj = symbol_slice(self); // take all
+ if(nobj) {
+ PyObject *ret = PySequence_Concat(nobj,op);
+ Py_DECREF(nobj);
+ return ret;
+ }
+ else
+ return NULL;
+}
+
+static PyObject *symbol_repeat(pySymbol *self,int rep)
+{
+ PyObject *nobj = symbol_slice(self); // take all
+ if(nobj) {
+ PyObject *ret = PySequence_Repeat(nobj,rep);
+ Py_DECREF(nobj);
+ return ret;
+ }
+ else
+ return NULL;
+}
+
+static PySequenceMethods symbol_as_seq = {
+ (inquiry)symbol_length, /* inquiry sq_length; __len__ */
+ (binaryfunc)symbol_concat, /* __add__ */
+ (intargfunc)symbol_repeat, /* __mul__ */
+ (intargfunc)symbol_item, /* intargfunc sq_item; __getitem__ */
+ (intintargfunc)symbol_slice, /* intintargfunc sq_slice; __getslice__ */
+ NULL, /* intobjargproc sq_ass_item; __setitem__ */
+ NULL, /* intintobjargproc sq_ass_slice; __setslice__ */
+};
+
+static PyObject *symbol_iter(PyObject *obj)
+{
+ pySymbol *self = (pySymbol *)obj;
+ PyObject *nobj = symbol_slice(self);
+ if(nobj) {
+ PyObject *it = PyObject_GetIter(nobj);
+ Py_DECREF(nobj);
+ return it;
+ }
+ else
+ return NULL;
+}
+
+
+
PyTypeObject pySymbol_Type = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
@@ -94,7 +177,7 @@ PyTypeObject pySymbol_Type = {
0, /*tp_compare*/
symbol_repr, /*tp_repr*/
0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
+ &symbol_as_seq, /*tp_as_sequence*/
0, /*tp_as_mapping*/
symbol_hash, /*tp_hash */
0, /*tp_call*/
@@ -108,7 +191,7 @@ PyTypeObject pySymbol_Type = {
0, /* tp_clear */
symbol_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
- 0, /* tp_iter */
+ symbol_iter, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */