Update of /cvsroot/pure-data/externals/grill/py/source
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4239/source
Modified Files:
	clmeth.cpp modmeth.cpp py.cpp pyargs.cpp pybase.cpp pybase.h 
	pyext.cpp pysymbol.cpp 
Added Files:
	pymeth.cpp 
Log Message:
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
Index: pysymbol.cpp
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/py/source/pysymbol.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -C2 -d -r1.2 -r1.3
*** pysymbol.cpp	19 Jan 2005 04:58:36 -0000	1.2
--- pysymbol.cpp	9 Jul 2005 13:03:34 -0000	1.3
***************
*** 82,85 ****
--- 82,168 ----
  }
  
+ 
+ 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)
***************
*** 95,99 ****
      symbol_repr,               /*tp_repr*/
      0,                         /*tp_as_number*/
!     0,                         /*tp_as_sequence*/
      0,                         /*tp_as_mapping*/
      symbol_hash,               /*tp_hash */
--- 178,182 ----
      symbol_repr,               /*tp_repr*/
      0,                         /*tp_as_number*/
!     &symbol_as_seq,            /*tp_as_sequence*/
      0,                         /*tp_as_mapping*/
      symbol_hash,               /*tp_hash */
***************
*** 109,113 ****
      symbol_richcompare,	       /* tp_richcompare */
      0,		               /* tp_weaklistoffset */
!     0,		               /* tp_iter */
      0,		               /* tp_iternext */
      0,                          /* tp_methods */
--- 192,196 ----
      symbol_richcompare,	       /* tp_richcompare */
      0,		               /* tp_weaklistoffset */
!     symbol_iter,		    /* tp_iter */
      0,		               /* tp_iternext */
      0,                          /* tp_methods */
Index: pyargs.cpp
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/py/source/pyargs.cpp,v
retrieving revision 1.16
retrieving revision 1.17
diff -C2 -d -r1.16 -r1.17
*** pyargs.cpp	8 Jul 2005 14:30:31 -0000	1.16
--- pyargs.cpp	9 Jul 2005 13:03:34 -0000	1.17
***************
*** 18,22 ****
  	if(flext::IsSymbol(at)) 
          return pySymbol_FromSymbol(flext::GetSymbol(at));
! /*
      else if(flext::CanbeInt(at) || flext::CanbeFloat(at)) {
          // if a number can be an integer... let it be an integer!
--- 18,22 ----
  	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!
***************
*** 25,34 ****
          return (double)ival == fval?PyInt_FromLong(ival):PyFloat_FromDouble(fval);
      }
! */
      else if(flext::IsFloat(at))
          return PyFloat_FromDouble(flext::GetFloat(at));
      else if(flext::IsInt(at))
          return PyInt_FromLong(flext::GetInt(at));
! 
      return NULL;
  }
--- 25,34 ----
          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;
  }
***************
*** 100,104 ****
          // ok!
      }
!     else if(argc == 1 && IsAtom(s))
  		ret = MakePyAtom(*argv);       
      else {
--- 100,105 ----
          // ok!
      }
!     else if(argc == 1 && !IsAnything(s))
!         // convert atoms and one-element lists
  		ret = MakePyAtom(*argv);       
      else {
***************
*** 126,130 ****
  }
  
! bool pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs)
  {
  	if(pValue == NULL) return false; 
--- 127,131 ----
  }
  
! const t_symbol *pybase::GetPyArgs(AtomList &lst,PyObject *pValue,int offs)
  {
  	if(pValue == NULL) return false; 
***************
*** 133,137 ****
  
  	int rargc = 0;
- 	bool ok = true;
  	retval tp = nothing;
  
--- 134,137 ----
***************
*** 153,156 ****
--- 153,158 ----
  	lst(offs+rargc);
  
+     const t_symbol *sym = NULL;
+ 
  	for(int ix = 0; ix < rargc; ++ix) {
  		PyObject *arg;
***************
*** 161,169 ****
  
          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));
  /*
          else if(ix == 0 && self && PyInstance_Check(arg)) {
--- 163,171 ----
  
          t_atom &at = lst[offs+ix];
!         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)) {
***************
*** 181,185 ****
  			Py_XDECREF(stp);
  			Py_XDECREF(tp);
! 			ok = false;
  		}
  
--- 183,188 ----
  			Py_XDECREF(stp);
  			Py_XDECREF(tp);
! 
!             SetSymbol(at,sym__); sym = sym_symbol;
  		}
  
***************
*** 188,204 ****
  	}
  
!     return ok;
  }
  
  
! bool 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);
      for(size_t i = 0; i < szat; ++i,atom >>= 16)
!         flext::SetInt(lst[i+1],(int)(atom&((1<<16)-1)));
!     return true;
  }
--- 191,208 ----
  	}
  
!     if(sym && tp == sequ) sym = sym_list;
! 
!     return sym;
  }
  
  
! const t_symbol *pybase::GetPyAtom(AtomList &lst,PyObject *obj)
  {
      size_t atom = PyAtom::Register(obj);
      size_t szat = sizeof(atom)/2;
  
!     lst(szat);
      for(size_t i = 0; i < szat; ++i,atom >>= 16)
!         flext::SetInt(lst[i],(int)(atom&((1<<16)-1)));
!     return symatom;
  }
--- NEW FILE: pymeth.cpp ---
/* 
py/pyext - python script object for PD and Max/MSP
Copyright (c)2002-2005 Thomas Grill (gr(a)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);
}
Index: modmeth.cpp
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/py/source/modmeth.cpp,v
retrieving revision 1.20
retrieving revision 1.21
diff -C2 -d -r1.20 -r1.21
*** modmeth.cpp	8 Jul 2005 14:30:31 -0000	1.20
--- modmeth.cpp	9 Jul 2005 13:03:34 -0000	1.21
***************
*** 129,139 ****
  
          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);
! 
  #ifdef FLEXT_DEBUG
              if(!ok)
--- 129,135 ----
  
          AtomListStatic<16> lst;
!         const t_symbol *sym = GetPyArgs(lst,val);
! 		if(sym) {
!     		bool ok = Forward(recv,sym,lst.Count(),lst.Atoms());
  #ifdef FLEXT_DEBUG
              if(!ok)
Index: clmeth.cpp
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/py/source/clmeth.cpp,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -d -r1.21 -r1.22
*** clmeth.cpp	8 Jul 2005 14:30:30 -0000	1.21
--- clmeth.cpp	9 Jul 2005 13:03:34 -0000	1.22
***************
*** 183,187 ****
              o += ext->sigoutlets;
  
!             if(ext->OutObject(ext,o,val))
      			ok = true;
  		    else 
--- 183,187 ----
              o += ext->sigoutlets;
  
!             if(ext->OutObject(ext,o-1,val))
      			ok = true;
  		    else 
***************
*** 296,304 ****
  
  		flext::AtomListStatic<16> lst;
!         if(GetPyArgs(lst,val)) {
  			t_glist *gl = ext->thisCanvas(); //canvas_getcurrent();
  			t_class **cl = (t_pd *)gl;
  			if(cl)
! 				pd_forwardmess(cl,lst.Count(),lst.Atoms());
  #ifdef FLEXT_DEBUG
  			else
--- 296,305 ----
  
  		flext::AtomListStatic<16> lst;
!         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());
  #ifdef FLEXT_DEBUG
  			else
Index: pybase.h
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/py/source/pybase.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** pybase.h	8 Jul 2005 14:30:31 -0000	1.1
--- pybase.h	9 Jul 2005 13:03:34 -0000	1.2
***************
*** 27,32 ****
  	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 void lib_setup();
--- 27,32 ----
  	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 const t_symbol *GetPyArgs(AtomList &lst,PyObject *pValue,int offs = 0);
! 	static const t_symbol *GetPyAtom(AtomList &lst,PyObject *pValue);
  
      static void lib_setup();
***************
*** 95,98 ****
--- 95,99 ----
  
  	static PyObject *module_obj,*module_dict;
+ 	static PyObject *builtins_obj,*builtins_dict;
  	static PyMethodDef func_tbl[];
  
***************
*** 162,165 ****
--- 163,168 ----
  #endif
  
+     static const t_symbol *sym_fint; // float or int symbol, depending on native number message type
+ 
  public:
  
Index: pybase.cpp
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/py/source/pybase.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** pybase.cpp	8 Jul 2005 14:30:31 -0000	1.1
--- pybase.cpp	9 Jul 2005 13:03:34 -0000	1.2
***************
*** 63,66 ****
--- 63,70 ----
  PyObject *pybase::module_dict = NULL;
  
+ PyObject *pybase::builtins_obj = NULL;
+ PyObject *pybase::builtins_dict = NULL;
+ 
+ const t_symbol *pybase::sym_fint = NULL;
  
  // -----------------------------------------------------------------------------------------------------------
***************
*** 129,132 ****
--- 133,139 ----
      }
  
+     builtins_obj = PyImport_ImportModule("__builtin__");
+ 	builtins_dict = PyModule_GetDict(builtins_obj); // borrowed reference
+ 
      // add symbol type
      initsymbol();
***************
*** 145,151 ****
--- 152,165 ----
      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);
***************
*** 214,219 ****
  		    PyErr_Print(); // no method found
  	    else {
!             if(!GetPyArgs(lst,pvar))
                  post("py/pyext - Argument list could not be created");
              Py_DECREF(pvar);
          }
--- 228,236 ----
  		    PyErr_Print(); // no method found
  	    else {
!             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);
          }
***************
*** 295,301 ****
  bool pybase::ImportModule(const char *name)
  {
! 	if(!name) return false;
!     if(modname == name) return true;
!     modname = name;
      return ReloadModule();
  }
--- 312,321 ----
  bool pybase::ImportModule(const char *name)
  {
!     if(name) {
!         if(modname == name) return true;
!         modname = name;
!     }
!     else
!         modname.clear();
      return ReloadModule();
  }
***************
*** 322,328 ****
  
      SetArgs();
!     PyObject *newmod = module
!         ?PyImport_ReloadModule(module)
!         :PyImport_ImportModule((char *)modname.c_str());
  
  	if(!newmod) {
--- 342,356 ----
  
      SetArgs();
!     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) {
***************
*** 416,428 ****
  {
      flext::AtomListStatic<16> lst;
!     if(xlate?GetPyArgs(lst,obj):GetPyAtom(lst,obj)) {
          // 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]);
          return true;
      }
--- 444,452 ----
  {
      flext::AtomListStatic<16> lst;
!     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
!         ext->ToOutAnything(o,sym,lst.Count(),lst.Atoms());
          return true;
      }
Index: pyext.cpp
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/py/source/pyext.cpp,v
retrieving revision 1.35
retrieving revision 1.36
diff -C2 -d -r1.35 -r1.36
*** pyext.cpp	8 Jul 2005 14:30:31 -0000	1.35
--- pyext.cpp	9 Jul 2005 13:03:34 -0000	1.36
***************
*** 421,425 ****
  	if(pvar) {
          flext::AtomListStatic<16> lst;
!         if(GetPyArgs(lst,pvar,1)) {
              // dump value to attribute outlet
              SetSymbol(lst[0],s);
--- 421,427 ----
  	if(pvar) {
          flext::AtomListStatic<16> lst;
!         const t_symbol *sym = GetPyArgs(lst,pvar,1);
!         if(sym) {
!             FLEXT_ASSERT(!IsAnything(sym));
              // dump value to attribute outlet
              SetSymbol(lst[0],s);
***************
*** 470,474 ****
  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);
  }
  
--- 472,479 ----
  bool pyext::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv)
  {
!     if(!n) 
!         return flext_dsp::CbMethodResort(n,s,argc,argv);
! 
! 	return pyobj && work(n,s,argc,argv);
  }
  
Index: py.cpp
===================================================================
RCS file: /cvsroot/pure-data/externals/grill/py/source/py.cpp,v
retrieving revision 1.26
retrieving revision 1.27
diff -C2 -d -r1.26 -r1.27
*** py.cpp	8 Jul 2005 14:30:31 -0000	1.26
--- py.cpp	9 Jul 2005 13:03:34 -0000	1.27
***************
*** 45,49 ****
  	virtual void Unload();
  
! 	bool SetFunction(const char *func);
  	bool ResetFunction();
  
--- 45,49 ----
  	virtual void Unload();
  
! 	bool SetFunction(const t_symbol *func);
  	bool ResetFunction();
  
***************
*** 123,131 ****
  	PyThreadState *state = PyLockSys();
  
!     int inlets = -1; // -1 signals non-explicit definition
      if(argc && CanbeInt(*argv)) {
          inlets = GetAInt(*argv);
          argv++,argc--;
      }
  
      if(inlets >= 1) {
--- 123,135 ----
  	PyThreadState *state = PyLockSys();
  
!     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) {
***************
*** 137,141 ****
  	AddOutAnything();  
  
!     const char *funnm = NULL;
  
  	// init script module
--- 141,145 ----
  	AddOutAnything();  
  
!     const t_symbol *funnm = NULL;
  
  	// init script module
***************
*** 152,164 ****
              char *pt = strrchr(modnm,'.'); // search for last dot
              if(pt && *pt) {
!                 funnm = pt+1;
                  *pt = 0;
-             }
  
!     		char dir[1024];
! 		    GetModulePath(modnm,dir,sizeof(dir));
! 		    AddToPath(dir);
  
! 			ImportModule(modnm);
          }
          else
--- 156,177 ----
              char *pt = strrchr(modnm,'.'); // search for last dot
              if(pt && *pt) {
!                 funnm = MakeSymbol(pt+1);
                  *pt = 0;
  
! #if 0
!                 if(!*modnm) 
!                     // if module name is empty set it to __builtin__
!                     strcpy(modnm,"__builtin__");
! #endif
!             }
  
!             if(*modnm) {
!     		    char dir[1024];
! 		        GetModulePath(modnm,dir,sizeof(dir));
! 		        AddToPath(dir);
!                 ImportModule(modnm);
!             }
!             else
!                 ImportModule(NULL);          
          }
          else
***************
*** 170,174 ****
      if(funnm || argc) {
          if(!funnm) {
! 	        funnm = GetAString(*argv);
              argv++,argc--;
          }
--- 183,187 ----
      if(funnm || argc) {
          if(!funnm) {
! 	        funnm = GetASymbol(*argv);
              argv++,argc--;
          }
***************
*** 226,230 ****
  
      if(argc) {
! 	    const char *fn = GetAString(*argv);
          if(fn)
  	        SetFunction(fn);
--- 239,243 ----
  
      if(argc) {
! 	    const t_symbol *fn = GetASymbol(*argv);
          if(fn)
  	        SetFunction(fn);
***************
*** 270,285 ****
  bool pyobj::ResetFunction()
  {
      function = NULL;
      
!     if(!module || !dict)
! 		post("%s - No module loaded",thisName());
      else {
          if(funname) {
  	        function = PyDict_GetItemString(dict,(char *)GetString(funname)); // borrowed!!!
              if(!function) 
                  PyErr_SetString(PyExc_AttributeError,"Function not found");
!             else if(!PyFunction_Check(function)) {
      		    function = NULL;
!                 PyErr_SetString(PyExc_TypeError,"Attribute is not a function");
              }
  	    }
--- 283,304 ----
  bool pyobj::ResetFunction()
  {
+     // function was borrowed from dict!
      function = NULL;
      
!     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(!PyCallable_Check(function)) {
      		    function = NULL;
!                 PyErr_SetString(PyExc_TypeError,"Attribute is not callable");
              }
  	    }
***************
*** 290,297 ****
  }
  
! bool pyobj::SetFunction(const char *func)
  {
  	if(func) {
! 		funname = MakeSymbol(func);
          withfunction = ResetFunction();
  	}
--- 309,316 ----
  }
  
! bool pyobj::SetFunction(const t_symbol *func)
  {
  	if(func) {
! 		funname = func;
          withfunction = ResetFunction();
  	}
***************
*** 308,312 ****
  void pyobj::LoadModule() 
  {
!     SetFunction(funname?GetString(funname):NULL);
  }
  
--- 327,331 ----
  void pyobj::LoadModule() 
  {
!     SetFunction(funname);
  }
  
***************
*** 343,350 ****
  bool pyobj::CbMethodResort(int n,const t_symbol *s,int argc,const t_atom *argv)
  {
      bool ret = false;
   
-     if(n == 0 && s != sym_bang) goto end;
- 
      if(objects && n >= 1) {
          // store args
--- 362,372 ----
  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(objects && n >= 1) {
          // store args
***************
*** 353,401 ****
          obj = MakePyArg(s,argc,argv); // steal reference
  
!         if(n > 1) {
!             ret = true; // just store, don't trigger
!             goto end;
!         }
      }
  
!     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]);
                  }
!             }
!             else
!                 // construct tuple from args
!                 pargs = MakePyArgs(s,argc,argv);
  
!             ret = gencall(function,pargs); // references are stolen
          }
! 	    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
- 		    PyErr_SetString(PyExc_RuntimeError,"No function set");
-     }
  
!     Report();
  
      PyUnlock(state);
--- 375,421 ----
          obj = MakePyArg(s,argc,argv); // steal reference
  
!         if(n > 1) ret = true; // just store, don't trigger
      }
  
!     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
!                     // if n == 0, it's a pure bang
!                     pargs = MakePyArgs(n?s:NULL,argc,argv);
  
!                 ret = gencall(function,pargs); // references are stolen
!             }
! 	        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
+ 		        PyErr_SetString(PyExc_RuntimeError,"No function set");
          }
  
!         Report();
!     }
  
      PyUnlock(state);
***************
*** 403,408 ****
      Respond(ret);
  
! end:
!     return ret || flext_base::CbMethodResort(n,s,argc,argv);
  }
  
--- 423,427 ----
      Respond(ret);
  
!     return ret;
  }