diff options
author | Thomas Grill <xovo@users.sourceforge.net> | 2007-03-07 13:40:14 +0000 |
---|---|---|
committer | Thomas Grill <xovo@users.sourceforge.net> | 2007-03-07 13:40:14 +0000 |
commit | 03c7468fcc51888c8271b904e4d6400ed5c1cbb1 (patch) | |
tree | 411627e2da0f574bba30fb6d6a5b772bff07e448 /externals | |
parent | 2f2aaa03a0ace959c6ff911d8b11b45f143c7d6e (diff) |
multiply inlets for py (hot and cold inlets)
small optimizations and fixes
use PyGILState_\*() functionality (enabled with PY_USE_GIL)
updates for DSP processing
__str__ method for pyext, to enable print self calls
added message bundle functionality (pyext.Bundle class)
enable compiled-only scripts (without .py)
enable optimization of Python code in reease build
let _inlets and _outlets default to 0
fix for numpy
some ASSERTs for explicitly created pyext classes (should be runtime checks i guess)
open editor for script under OS X
fixing numpy initialization quirks
enable symbol binding for all callables (not only functions and methods)
_isthreaded is now a data member instead of a method
fix for gcc4
added pyext._list and pyext._tuple to convert input lists to Python sequence objects
enable module packages (module/__init__.py[co]), now also for Max
python-like dotted module.function syntax
cleaned up float vs. int pyext tags
compiler flag to exclude DSP objects
some optimizations and py reload fix
more safety for calls where association python-pd has already been removed
always run Python interpreter in the background
svn path=/trunk/; revision=7474
Diffstat (limited to 'externals')
31 files changed, 2741 insertions, 2648 deletions
diff --git a/externals/grill/py/build/config-lnx.def b/externals/grill/py/build/config-lnx.def index e19f03bc..10e518f5 100644 --- a/externals/grill/py/build/config-lnx.def +++ b/externals/grill/py/build/config-lnx.def @@ -9,3 +9,6 @@ PYTHONVERSION=2.4 PY_NUMPY=1 # PY_NUMARRAY=1 # PY_NUMERIC=1 + +# use thread-safe GIL functionality (do this for python version >= 2.3!) +PY_USE_GIL=1
\ No newline at end of file diff --git a/externals/grill/py/build/config-mac.def b/externals/grill/py/build/config-mac.def index 57f6e3d5..752ee335 100644 --- a/externals/grill/py/build/config-mac.def +++ b/externals/grill/py/build/config-mac.def @@ -3,3 +3,6 @@ PY_NUMPY=1 # PY_NUMARRAY=1 # PY_NUMERIC=1 + +# use thread-safe GIL functionality (do this for python version >= 2.3!) +PY_USE_GIL=1
\ No newline at end of file diff --git a/externals/grill/py/build/config-win.def b/externals/grill/py/build/config-win.def index fee70e7b..98ab5552 100644 --- a/externals/grill/py/build/config-win.def +++ b/externals/grill/py/build/config-win.def @@ -9,3 +9,6 @@ PYTHONPATH=%programfiles%/python$(PYTHONVER) PY_NUMPY=1 # PY_NUMARRAY=1 # PY_NUMERIC=1 + +# use thread-safe GIL functionality (do this for python version >= 2.3!) +PY_USE_GIL=1
\ No newline at end of file diff --git a/externals/grill/py/build/gnumake-lnx-gcc.inc b/externals/grill/py/build/gnumake-lnx-gcc.inc index 483bb514..2babf197 100644 --- a/externals/grill/py/build/gnumake-lnx-gcc.inc +++ b/externals/grill/py/build/gnumake-lnx-gcc.inc @@ -12,3 +12,6 @@ ifdef PY_NUMERIC DEFS += -DPY_NUMERIC endif +ifdef PY_USE_GIL +DEFS += -DPY_USE_GIL +endif diff --git a/externals/grill/py/build/gnumake-mac-gcc.inc b/externals/grill/py/build/gnumake-mac-gcc.inc index c7080d47..8f8591af 100644 --- a/externals/grill/py/build/gnumake-mac-gcc.inc +++ b/externals/grill/py/build/gnumake-mac-gcc.inc @@ -12,3 +12,6 @@ ifdef PY_NUMERIC DEFS += -DPY_NUMERIC endif +ifdef PY_USE_GIL +DEFS += -DPY_USE_GIL +endif
\ No newline at end of file diff --git a/externals/grill/py/build/gnumake-win-cygwin.inc b/externals/grill/py/build/gnumake-win-cygwin.inc index 102c2ecd..d9487833 100644 --- a/externals/grill/py/build/gnumake-win-cygwin.inc +++ b/externals/grill/py/build/gnumake-win-cygwin.inc @@ -13,3 +13,6 @@ ifdef PY_NUMERIC DEFS += -DPY_NUMERIC endif +ifdef PY_USE_GIL +DEFS += -DPY_USE_GIL +endif
\ No newline at end of file diff --git a/externals/grill/py/build/nmake-win-msvc.inc b/externals/grill/py/build/nmake-win-msvc.inc index 0820daf9..a23e03ca 100644 --- a/externals/grill/py/build/nmake-win-msvc.inc +++ b/externals/grill/py/build/nmake-win-msvc.inc @@ -14,3 +14,6 @@ DEFS = $(DEFS) /DPY_NUMPY DEFS = $(DEFS) /DPY_NUMERIC !endif +!ifdef PY_USE_GIL +DEFS = $(DEFS) /DPY_USE_GIL +!endif diff --git a/externals/grill/py/package.txt b/externals/grill/py/package.txt index 001023bf..9002aa86 100644 --- a/externals/grill/py/package.txt +++ b/externals/grill/py/package.txt @@ -1,16 +1,16 @@ -NAME=py
-
-BUILDTYPE=multi
-BUILDDIR=build
-
-SRCDIR=source
-PRECOMPILE=pyprefix.h
-
-SRCS= \
- main.cpp \
- py.cpp pyext.cpp modmeth.cpp clmeth.cpp \
- register.cpp bound.cpp pyargs.cpp \
- pysymbol.cpp pybuffer.cpp pybundle.cpp pydsp.cpp \
- pyatom.cpp pybase.cpp pymeth.cpp
-
-HDRS= pyprefix.h main.h pyext.h pysymbol.h pybuffer.h pybundle.h pyatom.h pybase.h
+NAME=py + +BUILDTYPE=multi +BUILDDIR=build + +SRCDIR=source +PRECOMPILE=pyprefix.h + +SRCS= \ + main.cpp \ + py.cpp pyext.cpp modmeth.cpp clmeth.cpp \ + register.cpp bound.cpp pyargs.cpp \ + pysymbol.cpp pybuffer.cpp pybundle.cpp pydsp.cpp \ + pyatom.cpp pybase.cpp pymeth.cpp + +HDRS= pyprefix.h main.h pyext.h pysymbol.h pybuffer.h pybundle.h pyatom.h pybase.h diff --git a/externals/grill/py/py.vcproj b/externals/grill/py/py.vcproj index 74c3954c..0a42243a 100644 --- a/externals/grill/py/py.vcproj +++ b/externals/grill/py/py.vcproj @@ -86,7 +86,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="C:\data\prog\packs\pthreads\include;"c:\data\pd\pd-cvs\src";..\flext\source;C:\Programme\prog\Python24\include;"C:\Programme\prog\Python24\Lib\site-packages\numpy\core\include"" - PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PY_EXPORTS;FLEXT_SYS=2;FLEXT_THREADS;xPY_NUMPY;xFLEXT_USECMEM" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;PY_EXPORTS;FLEXT_SYS=2;FLEXT_THREADS;PY_NUMPY;FLEXT_USECMEM;PY_USE_GIL" BasicRuntimeChecks="3" RuntimeLibrary="1" RuntimeTypeInfo="TRUE" @@ -152,7 +152,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="c:\programme\audio\pd\src;c:\data\pdmax\flext\source;C:\Programme\prog\Python24\include" - PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FLEXT_SYS=2;FLEXT_THREADS;PY_EXPORTS;PY_NUMARRAY" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;FLEXT_SYS=2;FLEXT_THREADS;PY_EXPORTS;PY_NUMARRAY;PY_USE_GIL" StringPooling="TRUE" RuntimeLibrary="0" EnableFunctionLevelLinking="TRUE" @@ -167,7 +167,7 @@ <Tool Name="VCLinkerTool" AdditionalDependencies="pd.lib pthreadVC.lib" - OutputFile="pd-msvc\py.dll" + OutputFile="$(outdir)\py.dll" LinkIncremental="1" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="c:/programme/audio/pd/bin;"..\flext\pd-msvc";C:\Programme\prog\Python24\libs" diff --git a/externals/grill/py/py.xcodeproj/project.pbxproj b/externals/grill/py/py.xcodeproj/project.pbxproj index ae60f114..30e3c783 100644 --- a/externals/grill/py/py.xcodeproj/project.pbxproj +++ b/externals/grill/py/py.xcodeproj/project.pbxproj @@ -578,7 +578,12 @@ isa = XCBuildConfiguration; buildSettings = { GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = PY_NUMPY; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + _DEBUG, + PY_NUMPY, + PY_USE_GIL, + ); HEADER_SEARCH_PATHS = "/Library/Python/2.3/site-packages/numpy/core/include/"; }; name = Development; @@ -591,7 +596,12 @@ ppc, ); GCC_GENERATE_DEBUGGING_SYMBOLS = NO; - GCC_PREPROCESSOR_DEFINITIONS = PY_NUMPY; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + NDEBUG, + PY_NUMPY, + PY_USE_GIL, + ); HEADER_SEARCH_PATHS = "/Library/Python/2.3/site-packages/numpy/core/include/"; }; name = Deployment; diff --git a/externals/grill/py/readme.txt b/externals/grill/py/readme.txt index cba59e07..c10b2b6a 100644 --- a/externals/grill/py/readme.txt +++ b/externals/grill/py/readme.txt @@ -1,6 +1,6 @@ py/pyext - python script objects for PD and Max/MSP -Copyright (c)2002-2006 Thomas Grill (gr@grrrr.org) +Copyright (c)2002-2007 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. @@ -16,8 +16,9 @@ For OS X keep things as the are - it has Python installed by default. The py/pyext package should run with Python version >= 2.1. -It has been thoroughly tested with versions 2.2 to 2.4 +It has been thoroughly tested with versions 2.2 to 2.5 +The default build setting using PY_USE_GIL requires Python version >= 2.3. Check out the sample patches and scripts @@ -47,7 +48,6 @@ Known bugs: - With standard PD 0.37, threaded py scripts will cause "Stack overflows" under some circumstances -> use PD 0.38 or the devel_0_37 cvs branch instead - It has been reported that pyext crashes on AMD64 with SSE enabled (for these CPUs, disable the respective compiler flags) -- Threading in pyext obviously crashes under linux with Python version 2.4.2 (only) ---------------------------------------------------------------------------- @@ -120,6 +120,8 @@ Version history: - ADD: py.Bundle class to support flext message bundles - ADD: enable usage of compiled-only modules (.py[co]) - ADD: enable usage of module packages (with module/__init__.py[co]) +- ADD: make use of the PyGILState_*() functions +- ADD: always run the Python interpreter in the background (to keep alive Python threads) 0.2.0: - ADD: handling of Python threads diff --git a/externals/grill/py/scripts/buffer.py b/externals/grill/py/scripts/buffer.py index 2bd36203..46c47991 100644 --- a/externals/grill/py/scripts/buffer.py +++ b/externals/grill/py/scripts/buffer.py @@ -1,60 +1,60 @@ -# py/pyext - python script objects for PD and MaxMSP
-#
-# 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.
-#
-
-"""This is an example script for the py/pyext object's buffer support.
-
-PD/Max buffers can be mapped to Python arrays.
-Currently, there are three implementations:
-Numeric, numarray and Numeric3 (for all of them see http://numeric.scipy.org)
-"""
-
-import sys
-
-try:
- import pyext
-except:
- print "ERROR: This script must be loaded by the PD/Max py/pyext external"
-
-try:
- from numarray import *
-except:
- print "Failed importing numarray module:",sys.exc_value
-
-def mul(*args):
- # create buffer objects
- # as long as these variables live the underlying buffers are locked
- c = pyext.Buffer(args[0])
- a = pyext.Buffer(args[1])
- b = pyext.Buffer(args[2])
-
- # slicing causes Python arrays (mapped to buffers) to be created
- # note the c[:] - to assign contents you must assign to a slice of the buffer
- c[:] = a[:]*b[:]
-
-def add(*args):
- c = pyext.Buffer(args[0])
- a = pyext.Buffer(args[1])
- b = pyext.Buffer(args[2])
-
- # this is also possible, but is probably slower
- # the + converts a into a Python array, the argument b is taken as a sequence
- # depending on the implementation this may be as fast
- # as above or not
- c[:] = a+b
-
-def fadein(target):
- a = pyext.Buffer(target)
- # in place operations are ok
- a *= arange(len(a),type=Float32)/len(a)
-
-def neg(target):
- a = pyext.Buffer(target)
- # in place transformation (see Python array ufuncs)
- negative(a[:],a[:])
- # must mark buffer content as dirty to update graph
- # (no explicit assignment occurred)
- a.dirty()
+# py/pyext - python script objects for PD and MaxMSP +# +# 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. +# + +"""This is an example script for the py/pyext object's buffer support. + +PD/Max buffers can be mapped to Python arrays. +Currently, there are three implementations: +Numeric, numarray and Numeric3 (for all of them see http://numeric.scipy.org) +""" + +import sys + +try: + import pyext +except: + print "ERROR: This script must be loaded by the PD/Max py/pyext external" + +try: + from numarray import * +except: + print "Failed importing numarray module:",sys.exc_value + +def mul(*args): + # create buffer objects + # as long as these variables live the underlying buffers are locked + c = pyext.Buffer(args[0]) + a = pyext.Buffer(args[1]) + b = pyext.Buffer(args[2]) + + # slicing causes Python arrays (mapped to buffers) to be created + # note the c[:] - to assign contents you must assign to a slice of the buffer + c[:] = a[:]*b[:] + +def add(*args): + c = pyext.Buffer(args[0]) + a = pyext.Buffer(args[1]) + b = pyext.Buffer(args[2]) + + # this is also possible, but is probably slower + # the + converts a into a Python array, the argument b is taken as a sequence + # depending on the implementation this may be as fast + # as above or not + c[:] = a+b + +def fadein(target): + a = pyext.Buffer(target) + # in place operations are ok + a *= arange(len(a),type=Float32)/len(a) + +def neg(target): + a = pyext.Buffer(target) + # in place transformation (see Python array ufuncs) + negative(a[:],a[:]) + # must mark buffer content as dirty to update graph + # (no explicit assignment occurred) + a.dirty() diff --git a/externals/grill/py/scripts/sig.py b/externals/grill/py/scripts/sig.py index 8aa1ce65..09be7b66 100644 --- a/externals/grill/py/scripts/sig.py +++ b/externals/grill/py/scripts/sig.py @@ -1,100 +1,100 @@ -# py/pyext - python script objects for PD and MaxMSP
-#
-# 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.
-#
-
-"""This is an example script for the py/pyext signal support.
-
-For numarray see http://numeric.scipy.org
-It will probably once be replaced by Numeric(3)
-"""
-
-try:
- import pyext
-except:
- print "ERROR: This script must be loaded by the PD/Max py/pyext external"
-
-try:
- import psyco
- psyco.full()
- print "Using JIT compilation"
-except:
- # don't care
- pass
-
-import sys,math
-
-try:
- import numarray
-except:
- print "Failed importing numarray module:",sys.exc_value
-
-
-class gain(pyext._class):
- """Just a simple gain stage"""
-
- gain = 0
-
- def _signal(self):
- # Multiply input vector by gain and copy to output
- try:
- self._outvec(0)[:] = self._invec(0)*self.gain
- except:
- pass
-
-
-class gain2(pyext._class):
- """More optimized version"""
-
- gain = 0
-
- def _dsp(self):
- if not self._arraysupport():
- print "No DSP support"
- return False
-
- # cache vectors in this scope
- self.invec = self._invec(0)
- self.outvec = self._outvec(0)
- # initialize _signal method here for optimized version
- if self.invec is self.outvec:
- self._signal = self.signal1
- else:
- self._signal = self.signal2
- return True
-
- def signal1(self):
- # Multiply signal vector in place
- self.outvec *= self.gain
-
- def signal2(self):
- # Multiply input vector by gain and copy to output
- self.outvec[:] = self.invec*self.gain
-
-
-class pan(pyext._class):
- """Stereo panning"""
-
- def __init__(self):
- self.float_1(0.5)
-
- def float_1(self,pos):
- """pos ranges from 0 to 1"""
- x = pos*math.pi/2
- self.fl = math.cos(x)
- self.fr = math.sin(x)
-
- def _dsp(self):
- # if _dsp is present it must return True to enable DSP
- return pyext._arraysupport()
-
- def _signal(self):
- # Multiply input vector by gain and copy to output
- iv = self._invec(0)
- # first process right output channel because left one could be
- # identical to input
- # we could also test with 'self._outvec(1)[:] is iv'
- self._outvec(1)[:] = iv*self.fr
- self._outvec(0)[:] = iv*self.fl
+# py/pyext - python script objects for PD and MaxMSP +# +# 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. +# + +"""This is an example script for the py/pyext signal support. + +For numarray see http://numeric.scipy.org +It will probably once be replaced by Numeric(3) +""" + +try: + import pyext +except: + print "ERROR: This script must be loaded by the PD/Max py/pyext external" + +try: + import psyco + psyco.full() + print "Using JIT compilation" +except: + # don't care + pass + +import sys,math + +try: + import numarray +except: + print "Failed importing numarray module:",sys.exc_value + + +class gain(pyext._class): + """Just a simple gain stage""" + + gain = 0 + + def _signal(self): + # Multiply input vector by gain and copy to output + try: + self._outvec(0)[:] = self._invec(0)*self.gain + except: + pass + + +class gain2(pyext._class): + """More optimized version""" + + gain = 0 + + def _dsp(self): + if not self._arraysupport(): + print "No DSP support" + return False + + # cache vectors in this scope + self.invec = self._invec(0) + self.outvec = self._outvec(0) + # initialize _signal method here for optimized version + if self.invec is self.outvec: + self._signal = self.signal1 + else: + self._signal = self.signal2 + return True + + def signal1(self): + # Multiply signal vector in place + self.outvec *= self.gain + + def signal2(self): + # Multiply input vector by gain and copy to output + self.outvec[:] = self.invec*self.gain + + +class pan(pyext._class): + """Stereo panning""" + + def __init__(self): + self.float_1(0.5) + + def float_1(self,pos): + """pos ranges from 0 to 1""" + x = pos*math.pi/2 + self.fl = math.cos(x) + self.fr = math.sin(x) + + def _dsp(self): + # if _dsp is present it must return True to enable DSP + return pyext._arraysupport() + + def _signal(self): + # Multiply input vector by gain and copy to output + iv = self._invec(0) + # first process right output channel because left one could be + # identical to input + # we could also test with 'self._outvec(1)[:] is iv' + self._outvec(1)[:] = iv*self.fr + self._outvec(0)[:] = iv*self.fl diff --git a/externals/grill/py/scripts/simple.py b/externals/grill/py/scripts/simple.py index 04bea7ac..1aa211c5 100644 --- a/externals/grill/py/scripts/simple.py +++ b/externals/grill/py/scripts/simple.py @@ -1,6 +1,6 @@ # py/pyext - python script objects for PD and MaxMSP # -# Copyright (c) 2002-2005 Thomas Grill (gr@grrrr.org) +# Copyright (c) 2002-2007 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. # @@ -57,6 +57,8 @@ pyext Usage: self._outlet(outlet,arg1,arg2,arg3,arg4) ... where all args are atoms (no sequence types!) or self._outlet(outlet,arg) ... where arg is a sequence containing only atoms + + Do not use _outlet inside __init__, since the outlets have not been created at that time. - Use pyext functions and methods: See the __doc__ strings of the pyext module and the pyext._class base class. diff --git a/externals/grill/py/source/bound.cpp b/externals/grill/py/source/bound.cpp index 3e7bc386..de81bf1c 100644 --- a/externals/grill/py/source/bound.cpp +++ b/externals/grill/py/source/bound.cpp @@ -64,7 +64,7 @@ bool pyext::boundmeth(flext_base *th,t_symbol *sym,int argc,t_atom *argv,void *d bounddata *obj = (bounddata *)data; pyext *pyth = static_cast<pyext *>(th); - PyThreadState *state = pyth->PyLock(); + ThrState state = pyth->PyLock(); PyObject *args = MakePyArgs(sym,argc,argv); diff --git a/externals/grill/py/source/clmeth.cpp b/externals/grill/py/source/clmeth.cpp index be003291..e1e01977 100644 --- a/externals/grill/py/source/clmeth.cpp +++ b/externals/grill/py/source/clmeth.cpp @@ -2,7 +2,7 @@ py/pyext - python external object for PD and Max/MSP -Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org) +Copyright (c)2002-2007 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. @@ -43,7 +43,7 @@ PyMethodDef pyext::attr_tbl[] = const char *pyext::pyext_doc = - "py/pyext - python external object for PD and Max/MSP, (C)2002-2005 Thomas Grill\n" + "py/pyext - python external object for PD and Max/MSP, (C)2002-2007 Thomas Grill\n" "\n" "This is the pyext base class. Available methods:\n" "_outlet(self,ix,args...): Send a message to an indexed outlet\n" diff --git a/externals/grill/py/source/modmeth.cpp b/externals/grill/py/source/modmeth.cpp index 3d44d99e..52f5b964 100644 --- a/externals/grill/py/source/modmeth.cpp +++ b/externals/grill/py/source/modmeth.cpp @@ -2,7 +2,7 @@ py/pyext - python external object for PD and Max/MSP -Copyright (c)2002-2006 Thomas Grill (gr@grrrr.org) +Copyright (c)2002-2007 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. @@ -35,7 +35,7 @@ PyMethodDef pybase::func_tbl[] = }; const char *pybase::py_doc = - "py/pyext - python external object for PD and Max/MSP, (C)2002-2006 Thomas Grill\n" + "py/pyext - python external object for PD and Max/MSP, (C)2002-2007 Thomas Grill\n" "\n" "This is the pyext module. Available function:\n" "_send(args...): Send a message to a send symbol\n" diff --git a/externals/grill/py/source/py.cpp b/externals/grill/py/source/py.cpp index c773ffcb..f19ec36a 100644 --- a/externals/grill/py/source/py.cpp +++ b/externals/grill/py/source/py.cpp @@ -2,7 +2,7 @@ py/pyext - python script object for PD and Max/MSP -Copyright (c)2002-2005 Thomas Grill (gr@grrrr.org) +Copyright (c)2002-2007 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. @@ -117,7 +117,7 @@ pyobj::pyobj(int argc,const t_atom *argv) FLEXT_ADDTIMER(stoptmr,tick); #endif - PyThreadState *state = PyLockSys(); + ThrState state = PyLockSys(); int inlets; if(argc && CanbeInt(*argv)) { @@ -193,7 +193,7 @@ pyobj::~pyobj() delete[] objects; } - PyThreadState *state = PyLockSys(); + ThrState state = PyLockSys(); Unregister(GetRegistry(REGNAME)); Report(); PyUnlock(state); @@ -207,7 +207,7 @@ void pyobj::Exit() void pyobj::m_set(int argc,const t_atom *argv) { - PyThreadState *state = PyLockSys(); + ThrState state = PyLockSys(); // function name has precedence if(argc >= 2) { @@ -241,7 +241,7 @@ void pyobj::m_set(int argc,const t_atom *argv) void pyobj::m_help() { post(""); - post("%s %s - python script object, (C)2002-2006 Thomas Grill",thisName(),PY__VERSION); + post("%s %s - python script object, (C)2002-2007 Thomas Grill",thisName(),PY__VERSION); #ifdef FLEXT_DEBUG post("DEBUG VERSION, compiled on " __DATE__ " " __TIME__); #endif @@ -346,7 +346,7 @@ 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 = PyLockSys(); + ThrState state = PyLockSys(); bool ret = false; diff --git a/externals/grill/py/source/pyatom.cpp b/externals/grill/py/source/pyatom.cpp index 07712f30..0af1b5e0 100644 --- a/externals/grill/py/source/pyatom.cpp +++ b/externals/grill/py/source/pyatom.cpp @@ -1,61 +1,61 @@ -/*
-
-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 "pyatom.h"
-#include <map>
-
-#define INTV 0.01
-
-typedef std::map<size_t,PyObject *> ObjMap;
-
-static ObjMap objmap;
-static size_t collix = 0,curix = 0;
-static double last = 0;
-
-size_t PyAtom::Register(PyObject *obj)
-{
- Collect();
-
- Py_INCREF(obj);
- objmap[++curix] = obj;
-
-#ifdef _DEBUG
-// post("REG %p (%i)\n",obj,objmap.size());
-#endif
- return curix;
-}
-
-PyObject *PyAtom::Retrieve(size_t id)
-{
- ObjMap::iterator it = objmap.find(id);
- PyObject *ret = it == objmap.end()?NULL:it->second;
- Collect();
- return ret;
-}
-
-void PyAtom::Collect()
-{
- for(;;) {
- ObjMap::iterator it = objmap.begin();
- if(it == objmap.end() || it->first > collix) break;
-
- PyObject *obj = it->second;
- Py_DECREF(obj);
- objmap.erase(it);
-
-#ifdef _DEBUG
-// post("DEL %p\n",obj);
-#endif
- }
-
- // schedule next collect time
- double tm = flext::GetTime();
- if(tm > last+INTV) last = tm,collix = curix;
-}
+/* + +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 "pyatom.h" +#include <map> + +#define INTV 0.01 + +typedef std::map<size_t,PyObject *> ObjMap; + +static ObjMap objmap; +static size_t collix = 0,curix = 0; +static double last = 0; + +size_t PyAtom::Register(PyObject *obj) +{ + Collect(); + + Py_INCREF(obj); + objmap[++curix] = obj; + +#ifdef _DEBUG +// post("REG %p (%i)\n",obj,objmap.size()); +#endif + return curix; +} + +PyObject *PyAtom::Retrieve(size_t id) +{ + ObjMap::iterator it = objmap.find(id); + PyObject *ret = it == objmap.end()?NULL:it->second; + Collect(); + return ret; +} + +void PyAtom::Collect() +{ + for(;;) { + ObjMap::iterator it = objmap.begin(); + if(it == objmap.end() || it->first > collix) break; + + PyObject *obj = it->second; + Py_DECREF(obj); + objmap.erase(it); + +#ifdef _DEBUG +// post("DEL %p\n",obj); +#endif + } + + // schedule next collect time + double tm = flext::GetTime(); + if(tm > last+INTV) last = tm,collix = curix; +} diff --git a/externals/grill/py/source/pyatom.h b/externals/grill/py/source/pyatom.h index e96514c6..3c20c66b 100644 --- a/externals/grill/py/source/pyatom.h +++ b/externals/grill/py/source/pyatom.h @@ -1,19 +1,19 @@ -/*
-
-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 "main.h"
-
-class PyAtom
-{
-public:
- static size_t Register(PyObject *obj);
- static PyObject *Retrieve(size_t id);
- static void Collect();
-};
+/* + +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 "main.h" + +class PyAtom +{ +public: + static size_t Register(PyObject *obj); + static PyObject *Retrieve(size_t id); + static void Collect(); +}; diff --git a/externals/grill/py/source/pybase.cpp b/externals/grill/py/source/pybase.cpp index 5c9dd40c..a74df81e 100644 --- a/externals/grill/py/source/pybase.cpp +++ b/externals/grill/py/source/pybase.cpp @@ -1,881 +1,912 @@ -/*
-
-py/pyext - python external object for PD and MaxMSP
-
-Copyright (c)2002-2006 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>
-
-#if FLEXT_OS == FLEXT_OS_WIN
-#include <windows.h>
-#elif FLEXT_OS == FLEXT_OS_MAC
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-static PyMethodDef StdOut_Methods[] =
-{
- { "write", pybase::StdOut_Write, 1 },
- { NULL, NULL, }
-};
-
-static PyObject *gcollect = NULL;
-
-#ifdef FLEXT_THREADS
-
-class ThrCmp
-{
-public:
- inline bool operator()(const flext::thrid_t &a,const flext::thrid_t &b) const
- {
- if(sizeof(a) == sizeof(size_t))
- return *(size_t *)&a < *(size_t *)&b;
- else
- return memcmp(&a,&b,sizeof(a)) < 0;
- }
-};
-
-typedef std::map<flext::thrid_t,PyThreadState *,ThrCmp> PyThrMap;
-
-static PyInterpreterState *pymain = NULL;
-static PyThrMap pythrmap;
-PyThreadState *pybase::pythrsys = NULL;
-
-int pybase::lockcount = 0;
-
-PyThreadState *pybase::FindThreadState()
-{
- flext::thrid_t id = flext::GetThreadId();
- PyThrMap::iterator it = pythrmap.find(id);
- if(it == pythrmap.end()) {
- // Make new thread state
- PyThreadState *st = PyThreadState_New(pymain);
- pythrmap[id] = st;
- return st;
- }
- else
- return it->second;
-}
-
-void pybase::FreeThreadState()
-{
- flext::thrid_t id = flext::GetThreadId();
- PyThrMap::iterator it = pythrmap.find(id);
- if(it != pythrmap.end()) {
- // clear out any cruft from thread state object
- PyThreadState_Clear(it->second);
- // delete my thread state object
- PyThreadState_Delete(it->second);
- // delete from map
- pythrmap.erase(it);
- }
-}
-
-PyFifo pybase::qufifo;
-flext::ThrCond pybase::qucond;
-#endif
-
-
-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;
-const t_symbol *pybase::sym_response = NULL;
-
-// -----------------------------------------------------------------------------------------------------------
-
-
-void initsymbol();
-void initsamplebuffer();
-void initbundle();
-
-void pybase::lib_setup()
-{
- post("");
- post("------------------------------------------------");
- post("py/pyext %s - python script objects",PY__VERSION);
- post("(C)2002-2006 Thomas Grill - http://grrrr.org/ext");
- post("");
- post("using Python %s",Py_GetVersion());
-
-#ifdef FLEXT_DEBUG
- post("");
- post("DEBUG version compiled on %s %s",__DATE__,__TIME__);
-#endif
-
- // -------------------------------------------------------------
-
- sym_response = flext::MakeSymbol("response");
-
-#if FLEXT_SYS == FLEXT_SYS_PD
- sym_fint = sym_float;
-#else
- sym_fint = sym_int;
-#endif
-
- // -------------------------------------------------------------
-
- Py_Initialize();
-
-#ifdef FLEXT_DEBUG
- Py_DebugFlag = 1;
-// Py_VerboseFlag = 1;
-#else
- Py_OptimizeFlag = 1;
-#endif
-
-#ifdef FLEXT_THREADS
- // enable thread support and acquire the global thread lock
- PyEval_InitThreads();
-
- // get thread state
- pythrsys = PyThreadState_Get();
- // get main interpreter state
- pymain = pythrsys->interp;
-
- // add thread state of main thread to map
- pythrmap[GetThreadId()] = pythrsys;
-#endif
-
- // sys.argv must be set to empty tuple
- char *nothing = "";
- PySys_SetArgv(0,¬hing);
-
- // register/initialize pyext module only once!
- module_obj = Py_InitModule(PYEXT_MODULE, func_tbl);
- module_dict = PyModule_GetDict(module_obj); // borrowed reference
-
- PyModule_AddStringConstant(module_obj,"__doc__",(char *)py_doc);
-
- // redirect stdout
- PyObject* py_out;
- py_out = Py_InitModule("stdout", StdOut_Methods);
- PySys_SetObject("stdout", py_out);
- py_out = Py_InitModule("stderr", StdOut_Methods);
- PySys_SetObject("stderr", py_out);
-
- // get garbage collector function
- PyObject *gcobj = PyImport_ImportModule("gc");
- if(gcobj) {
- gcollect = PyObject_GetAttrString(gcobj,"collect");
- 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);
-
- // pre-defined symbols
- PyModule_AddObject(module_obj,"_s_",(PyObject *)pySymbol__);
- PyModule_AddObject(module_obj,"_s_bang",(PyObject *)pySymbol_bang);
- PyModule_AddObject(module_obj,"_s_list",(PyObject *)pySymbol_list);
- PyModule_AddObject(module_obj,"_s_symbol",(PyObject *)pySymbol_symbol);
- PyModule_AddObject(module_obj,"_s_float",(PyObject *)pySymbol_float);
- PyModule_AddObject(module_obj,"_s_int",(PyObject *)pySymbol_int);
-
- // add samplebuffer type
- initsamplebuffer();
- PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type);
-
- // add message bundle type
- initbundle();
- PyModule_AddObject(module_obj,"Bundle",(PyObject *)&pyBundle_Type);
-
- // -------------------------------------------------------------
-
- FLEXT_SETUP(pyobj);
- FLEXT_SETUP(pymeth);
- FLEXT_SETUP(pyext);
-#ifndef PY_NODSP
- FLEXT_DSP_SETUP(pydsp);
-#endif
-
-#ifdef FLEXT_THREADS
- // release global lock
- PyEval_ReleaseLock();
-
- // launch thread worker
- LaunchThread(quworker,NULL);
-#endif
-
- post("------------------------------------------------");
- post("");
-}
-
-FLEXT_LIB_SETUP(py,pybase::lib_setup)
-
-
-// -----------------------------------------------------------------------------------------------------------
-
-
-pybase::pybase()
- : module(NULL)
- , dict(NULL)
-#ifdef FLEXT_THREADS
- , thrcount(0)
- , shouldexit(false),stoptick(0)
-#endif
- , detach(0)
- , pymsg(false)
-{
- PyThreadState *state = PyLock();
- Py_INCREF(module_obj);
- PyUnlock(state);
-}
-
-pybase::~pybase()
-{
- PyThreadState *state = PyLock();
- Py_XDECREF(module_obj);
- PyUnlock(state);
-}
-
-void pybase::Exit()
-{
-#ifdef FLEXT_THREADS
- erasethreads();
-
- shouldexit = true;
- qucond.Signal();
-
- if(thrcount) {
- // Wait for a certain time
- for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i)
- Sleep(PY_STOP_TICK*0.001f);
- if(thrcount) {
- // Wait forever
- post("py/pyext - Waiting for thread termination!");
- while(thrcount) Sleep(PY_STOP_TICK*0.001f);
- post("py/pyext - Okay, all threads have terminated");
- }
- }
-#endif
-}
-
-void pybase::GetDir(PyObject *obj,AtomList &lst)
-{
- if(obj) {
- PyThreadState *state = PyLock();
-
- PyObject *pvar = PyObject_Dir(obj);
- if(!pvar)
- 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);
- }
-
- PyUnlock(state);
- }
-}
-
-void pybase::m__dir(PyObject *obj)
-{
- AtomList lst;
- GetDir(obj,lst);
- // dump dir to attribute outlet
- DumpOut(NULL,lst.Count(),lst.Atoms());
-}
-
-void pybase::m__doc(PyObject *obj)
-{
- if(obj) {
- PyThreadState *state = PyLock();
-
- PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!!
- if(docf && PyString_Check(docf)) {
- post("");
- const char *s = PyString_AS_STRING(docf);
-
- // FIX: Python doc strings can easily be larger than 1k characters
- // -> split into separate lines
- for(;;) {
- char buf[1024];
- char *nl = strchr((char *)s,'\n'); // the cast is for Borland C++
- if(!nl) {
- // no more newline found
- post(s);
- break;
- }
- else {
- // copy string before newline to temp buffer and post
- unsigned int l = nl-s;
- if(l >= sizeof(buf)) l = sizeof buf-1;
- strncpy(buf,s,l); // copy all but newline
- buf[l] = 0;
- post(buf);
- s = nl+1; // set after newline
- }
- }
- }
-
- PyUnlock(state);
- }
-}
-
-void pybase::OpenEditor()
-{
- if(!module) return;
- const char *mname = PyModule_GetFilename(module);
- if(!mname) {
- PyErr_Clear();
- return;
- }
-
- char fname[1024];
- strcpy(fname,mname);
-
- // replacing .pyc or .pyo for source file name
- char *dt = strrchr(fname,'.');
- if(dt && !strncmp(dt,".py",2)) strcpy(dt,".py");
-
- // this should open the editor....
-#if FLEXT_OS == FLEXT_OS_WIN
- int err = (int)ShellExecute(NULL,"edit",fname,NULL,NULL,SW_SHOW);
- if(err == SE_ERR_NOASSOC) {
- // no association found - try notepad
- err = (int)ShellExecute(NULL,NULL,"notepad.exe",fname,NULL,SW_SHOW);
- }
- else if(err == ERROR_FILE_NOT_FOUND || err == SE_ERR_FNF)
- post("py/pyext - File not %s found",fname);
- else if(err <= 32)
- post("py/pyext - Unknown error opening %s",fname);
-
-#elif FLEXT_OS == FLEXT_OS_MAC
- FSRef ref;
- OSStatus err = FSPathMakeRef((unsigned char *)fname,&ref,NULL);
- if(err)
- post("py/pyext - Error interpreting path %s",fname);
- else {
- FSRef editor;
- err = LSGetApplicationForItem(&ref,kLSRolesEditor,&editor,NULL);
- if(err) {
- // Can't find associated application... try Textedit
- err = FSPathMakeRef((unsigned char *)"/Applications/TextEdit.app",&editor,NULL);
- if(err)
- post("py/pyext - Can't find Textedit application");
- }
-
- if(!err) {
- LSLaunchFSRefSpec lspec;
- lspec.appRef = &editor;
- lspec.numDocs = 1;
- lspec.itemRefs = &ref;
- lspec.passThruParams = NULL;
- lspec.launchFlags = kLSLaunchDefaults;
- lspec.asyncRefCon = NULL;
- err = LSOpenFromRefSpec(&lspec,NULL);
- if(err)
- post("py/pyext - Couldn't launch editor");
- }
- }
-#else
- // thanks to Tim Blechmann
-
- char *editor = getenv("EDITOR");
-
- if(!editor) { // || !strcmp(editor, "/usr/bin/nano") || !strcmp(editor, "/usr/bin/pico") || !strcmp(editor, "/usr/bin/vi")) {
- // no environment variable or console text editor found ... use idle instead (should have come with Python)
- editor = "idle";
- }
-
- pid_t child = fork();
- if(!child) {
- char cmd[80];
- strcpy(cmd,editor);
- strcat(cmd," ");
- strcat(cmd,fname);
- execl("/bin/sh", "sh", "-c", cmd, (char *) NULL);
- }
-#endif
-}
-
-void pybase::SetArgs()
-{
- // script arguments
- int argc = args.Count();
- const t_atom *argv = args.Atoms();
- char **sargv = new char *[argc+1];
- for(int i = 0; i <= argc; ++i) {
- sargv[i] = new char[256];
- if(!i)
- strcpy(sargv[i],"py/pyext");
- else
- GetAString(argv[i-1],sargv[i],255);
- }
-
- // the arguments to the module are only recognized once! (at first use in a patcher)
- PySys_SetArgv(argc+1,sargv);
-
- for(int j = 0; j <= argc; ++j) delete[] sargv[j];
- delete[] sargv;
-}
-
-static bool getmodulesub(const char *mod,char *dir,int len,char *ext)
-{
-#if FLEXT_SYS == FLEXT_SYS_PD
- char *name;
- int fd = open_via_path("",mod,ext,dir,&name,len,0);
- if(fd > 0) {
- FLEXT_ASSERT(name && *name);
- close(fd);
- }
- else {
- // look for mod/__init__.py
- std::string tmp(mod);
- int l = tmp.size();
- tmp += "/__init__";
- fd = open_via_path("",tmp.c_str(),ext,dir,&name,len,0);
- if(fd > 0) {
- FLEXT_ASSERT(name && *name);
- close(fd);
- // we must remove the module name from dir
- char *t = dir+strlen(dir)-l;
- FLEXT_ASSERT(!strcmp(mod,t) && t[-1] == '/');
- t[-1] = 0;
- }
- else
- name = NULL;
- }
-
- // if dir is current working directory... name points to dir
- if(dir == name) strcpy(dir,".");
- return name != NULL;
-#elif FLEXT_SYS == FLEXT_SYS_MAX
- short path;
- long type;
- char smod[1024];
- strcpy(smod,mod);
- strcat(smod,ext);
- bool ok = !locatefile_extended(smod,&path,&type,&type,0);
- if(ok)
- // convert pathname to unix style
- path_topathname(path,NULL,smod);
- else {
- // do path/file.ext combinations work at all under Max?
- strcpy(smod,mod);
-
- short path;
- type = 'fold';
- ok = !locatefile_extended(smod,&path,&type,&type,1);
- if(ok) {
- // convert pathname to unix style (including trailing slash)
- path_topathname(path,NULL,smod);
- char *end = smod+strlen(smod);
- strcpy(end,mod);
- strcat(end,"/__init__");
- strcat(end,ext);
-
- // check if file is really existing: try to open it
- FILE *f = fopen(smod,"r");
- if(f) {
- *end = 0; // clear module part ... we only need base path
- fclose(f);
- }
- else
- ok = false;
- }
- }
-
- if(ok) {
- // convert path into slash style needed for Python
-#if 0
- // Max API function uses Volume:/Path notation
- path_nameconform(smod,dir,PATH_STYLE_SLASH,PATH_TYPE_ABSOLUTE);
-#else
-#if FLEXT_OS == FLEXT_OS_WIN
- char *colon = NULL;
-#else
- char *colon = strchr(smod,':');
-#endif
- if(colon) {
- *colon = 0;
- strcpy(dir,"/Volumes/");
- strcat(dir,smod);
- strcat(dir,colon+1);
- }
- else
- strcpy(dir,smod);
-#endif
- return true;
- }
- else
- // not found
- return false;
-#else
-#pragma message("Not implemented");
- return false;
-#endif
-}
-
-static bool getmodulepath(const char *mod,char *dir,int len)
-{
- return
- getmodulesub(mod,dir,len,".py") ||
- getmodulesub(mod,dir,len,".pyc") ||
- getmodulesub(mod,dir,len,".pyo");
-}
-
-bool pybase::ImportModule(const char *name)
-{
- if(name) {
- if(modname == name) {
- // module with the same name is already loaded
- if(module) return true;
- }
- else
- modname = name;
- }
- else
- modname.clear();
-
- UnimportModule();
- return ReloadModule();
-}
-
-void pybase::UnimportModule()
-{
- if(module) {
- FLEXT_ASSERT(dict && module_obj && module_dict);
-
- Py_DECREF(module);
-
- // reference count to module is not 0 here, altough probably the last instance was unloaded
- // Python retains one reference to the module all the time
- // we don't care
-
- module = NULL;
- dict = NULL;
- }
-}
-
-bool pybase::ReloadModule()
-{
- SetArgs();
- PyObject *newmod;
-
- if(modname.length()) {
- if(module)
- newmod = PyImport_ReloadModule(module);
- else {
- // search in module path (TODO: check before if module is already present to avoid costly searching)
- char dir[1024];
- if(!getmodulepath(modname.c_str(),dir,sizeof(dir)))
- PyErr_SetString(PyExc_ImportError,"Module not found in path");
- else
- AddToPath(dir);
-
- // module could also be loaded ok, even if it's not in the path (e.g. for internal stuff)
- newmod = 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
- UnimportModule();
- return false;
- }
- else {
- Py_XDECREF(module);
- module = newmod;
- dict = PyModule_GetDict(module); // borrowed
- return true;
- }
-}
-
-void pybase::AddToPath(const char *dir)
-{
- if(dir && *dir) {
- PyObject *pobj = PySys_GetObject("path");
- if(pobj && PyList_Check(pobj)) {
- PyObject *ps = PyString_FromString(dir);
- if(!PySequence_Contains(pobj,ps))
- PyList_Append(pobj,ps); // makes new reference
- Py_DECREF(ps);
- }
- PySys_SetObject("path",pobj); // steals reference to pobj
- }
-}
-
-void pybase::AddCurrentPath(flext_base *o)
-{
- char dir[1024];
-
- // add dir of current patch to path
- o->GetCanvasDir(dir,sizeof(dir));
- if(*dir) AddToPath(dir);
-
- // add current dir to path
-#if FLEXT_SYS == FLEXT_SYS_PD
- AddToPath(GetString(canvas_getcurrentdir()));
-#elif FLEXT_SYS == FLEXT_SYS_MAX
- short path = path_getdefault();
- path_topathname(path,NULL,dir);
- AddToPath(dir);
-#endif
-}
-
-bool pybase::OutObject(flext_base *ext,int o,PyObject *obj)
-{
- flext::AtomListStatic<16> lst;
- const t_symbol *sym = pymsg?GetPyAtom(lst,obj):GetPyArgs(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;
- }
- else
- return false;
-}
-
-void pybase::Reload()
-{
- PyThreadState *state = PyLock();
-
- 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;
-
-// post to the console
-PyObject* pybase::StdOut_Write(PyObject* self, PyObject* args)
-{
- // should always be a tuple
- FLEXT_ASSERT(PyTuple_Check(args));
-
- const int sz = PyTuple_GET_SIZE(args);
-
- for(int i = 0; i < sz; ++i) {
- PyObject *val = PyTuple_GET_ITEM(args,i); // borrowed reference
- PyObject *str = PyObject_Str(val); // new reference
- char *cstr = PyString_AS_STRING(str);
- char *lf = strchr(cstr,'\n');
-
- // line feed in string
- if(!lf) {
- // no -> just append
- if(output)
- PyString_ConcatAndDel(&output,str); // str is decrefd
- else
- output = str; // take str reference
- }
- else {
- // yes -> append up to line feed, reset output buffer to string remainder
- PyObject *part = PyString_FromStringAndSize(cstr,lf-cstr); // new reference
- if(output)
- PyString_ConcatAndDel(&output,part); // str is decrefd
- else
- output = part; // take str reference
-
- // output concatenated string
- post(PyString_AS_STRING(output));
-
- Py_DECREF(output);
- output = PyString_FromString(lf+1); // new reference
- }
- }
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-
-class work_data
-{
-public:
- work_data(PyObject *f,PyObject *a): fun(f),args(a) {}
- ~work_data() { Py_DECREF(fun); Py_DECREF(args); }
-
- PyObject *fun,*args;
-};
-
-bool pybase::gencall(PyObject *pmeth,PyObject *pargs)
-{
- bool ret = false;
-
- // Now call method
- switch(detach) {
- case 0:
- ret = docall(pmeth,pargs);
- Py_DECREF(pargs);
- Py_DECREF(pmeth);
- break;
-#ifdef FLEXT_THREADS
- case 1:
- // put call into queue
- ret = qucall(pmeth,pargs);
- break;
- case 2:
- // each call a new thread
- if(!shouldexit) {
- thr_params *p = new thr_params;
- p->cl = (flext_base *)this;
- p->var->_ext = new work_data(pmeth,pargs);
- ret = LaunchThread(thrworker,p);
- if(!ret) post("py/pyext - Failed to launch thread!");
- }
- break;
-#endif
- default:
- post("py/pyext - Unknown detach mode");
- }
- return ret;
-}
-
-void pybase::exchandle()
-{
-#if 0
- // want to use that, but exception keeps a reference to the object
- // might be a Python bug!
- PyErr_Print();
-#else
- // must use that instead... clear the exception
- PyObject *type,*value,*traceback;
- PyErr_Fetch(&type,&value,&traceback);
- PyErr_NormalizeException(&type,&value,&traceback);
- PyErr_Display(type,value,traceback);
-
- Py_XDECREF(type);
- Py_XDECREF(value);
- Py_XDECREF(traceback);
-#endif
-}
-
-#ifdef FLEXT_THREADS
-void pybase::thrworker(thr_params *p)
-{
- FLEXT_ASSERT(p);
- pybase *th = (pybase *)p->cl;
- work_data *w = (work_data *)p->var->_ext;
-
- ++th->thrcount; // \todo this should be atomic
- PyThreadState *state = PyLock();
-
- // call worker
- th->docall(w->fun,w->args);
- delete w;
-
- PyUnlock(state);
- --th->thrcount; // \todo this should be atomic
-}
-
-void pybase::quworker(thr_params *)
-{
- FifoEl *el;
- PyThreadState *my = FindThreadState(),*state;
-
- for(;;) {
- while(el = qufifo.Get()) {
- ++el->th->thrcount; // \todo this should be atomic
- state = PyLock(my);
- el->th->docall(el->fun,el->args);
- Py_XDECREF(el->fun);
- Py_XDECREF(el->args);
- PyUnlock(state);
- --el->th->thrcount; // \todo this should be atomic
- qufifo.Free(el);
- }
- qucond.Wait();
- }
-
- // we never end
-#if 0
- state = PyLock(my);
- // unref remaining Python objects
- while(el = qufifo.Get()) {
- Py_XDECREF(el->fun);
- Py_XDECREF(el->args);
- qufifo.Free(el);
- }
- PyUnlock(state);
-#endif
-}
-
-void pybase::erasethreads()
-{
- PyFifo tmp;
- FifoEl *el;
- while(el = qufifo.Get()) {
- if(el->th == this) {
- Py_XDECREF(el->fun);
- Py_XDECREF(el->args);
- qufifo.Free(el);
- }
- else
- tmp.Put(el);
- }
- // Push back
- while(el = tmp.Get()) qufifo.Put(el);
-}
-#endif
-
-bool pybase::collect()
-{
- if(gcollect) {
- PyObject *ret = PyObject_CallObject(gcollect,NULL);
- if(ret) {
-#ifdef FLEXT_DEBUG
- int refs = PyInt_AsLong(ret);
- if(refs) post("py/pyext - Garbage collector reports %i unreachable objects",refs);
-#endif
- Py_DECREF(ret);
- return false;
- }
- }
- return true;
-}
+/* + +py/pyext - python external object for PD and MaxMSP + +Copyright (c)2002-2007 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> + +#if FLEXT_OS == FLEXT_OS_WIN +#include <windows.h> +#elif FLEXT_OS == FLEXT_OS_MAC +#include <ApplicationServices/ApplicationServices.h> +#endif + +static PyMethodDef StdOut_Methods[] = +{ + { "write", pybase::StdOut_Write, 1 }, + { NULL, NULL, } +}; + +static PyObject *gcollect = NULL; + +#ifdef FLEXT_THREADS + +class ThrCmp +{ +public: + inline bool operator()(const flext::thrid_t &a,const flext::thrid_t &b) const + { + if(sizeof(a) == sizeof(size_t)) + return *(size_t *)&a < *(size_t *)&b; + else + return memcmp(&a,&b,sizeof(a)) < 0; + } +}; + + +int pybase::lockcount = 0; + +#ifndef PY_USE_GIL +static PyInterpreterState *pymain = NULL; + +typedef std::map<flext::thrid_t,ThrState,ThrCmp> PyThrMap; + +static PyThrMap pythrmap; +ThrState pybase::pythrsys = NULL; + +ThrState pybase::FindThreadState() +{ + flext::thrid_t id = flext::GetThreadId(); + PyThrMap::iterator it = pythrmap.find(id); + if(it == pythrmap.end()) { + // Make new thread state + ThrState st = PyThreadState_New(pymain); + pythrmap[id] = st; + return st; + } + else + return it->second; +} + +void pybase::FreeThreadState() +{ + flext::thrid_t id = flext::GetThreadId(); + PyThrMap::iterator it = pythrmap.find(id); + if(it != pythrmap.end()) { + // clear out any cruft from thread state object + PyThreadState_Clear(it->second); + // delete my thread state object + PyThreadState_Delete(it->second); + // delete from map + pythrmap.erase(it); + } +} +#endif // PY_USE_GIL + +PyFifo pybase::qufifo; +flext::ThrCond pybase::qucond; +#endif + + +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; +const t_symbol *pybase::sym_response = NULL; + +// ----------------------------------------------------------------------------------------------------------- + + +void initsymbol(); +void initsamplebuffer(); +void initbundle(); + +void pybase::lib_setup() +{ + post(""); + post("------------------------------------------------"); + post("py/pyext %s - python script objects",PY__VERSION); + post("(C)2002-2007 Thomas Grill - http://grrrr.org/ext"); + post(""); + post("using Python %s",Py_GetVersion()); + +#ifdef FLEXT_DEBUG + post(""); + post("DEBUG version compiled on %s %s",__DATE__,__TIME__); +#endif + + // ------------------------------------------------------------- + + sym_response = flext::MakeSymbol("response"); + +#if FLEXT_SYS == FLEXT_SYS_PD + sym_fint = sym_float; +#else + sym_fint = sym_int; +#endif + + // ------------------------------------------------------------- + + Py_Initialize(); + +#ifdef FLEXT_DEBUG + Py_DebugFlag = 1; +// Py_VerboseFlag = 1; +#else + Py_OptimizeFlag = 1; +#endif + +#ifdef FLEXT_THREADS + // enable thread support and acquire the global thread lock + PyEval_InitThreads(); + +#ifndef PY_USE_GIL + // get thread state + pythrsys = PyThreadState_Get(); + // get main interpreter state + pymain = pythrsys->interp; + + // add thread state of main thread to map + pythrmap[GetThreadId()] = pythrsys; +#endif // PY_USE_GIL + +#endif + + // sys.argv must be set to empty tuple + char *nothing = ""; + PySys_SetArgv(0,¬hing); + + // register/initialize pyext module only once! + module_obj = Py_InitModule(PYEXT_MODULE, func_tbl); + module_dict = PyModule_GetDict(module_obj); // borrowed reference + + PyModule_AddStringConstant(module_obj,"__doc__",(char *)py_doc); + + // redirect stdout + PyObject* py_out; + py_out = Py_InitModule("stdout", StdOut_Methods); + PySys_SetObject("stdout", py_out); + py_out = Py_InitModule("stderr", StdOut_Methods); + PySys_SetObject("stderr", py_out); + + // get garbage collector function + PyObject *gcobj = PyImport_ImportModule("gc"); + if(gcobj) { + gcollect = PyObject_GetAttrString(gcobj,"collect"); + 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); + + // pre-defined symbols + PyModule_AddObject(module_obj,"_s_",(PyObject *)pySymbol__); + PyModule_AddObject(module_obj,"_s_bang",(PyObject *)pySymbol_bang); + PyModule_AddObject(module_obj,"_s_list",(PyObject *)pySymbol_list); + PyModule_AddObject(module_obj,"_s_symbol",(PyObject *)pySymbol_symbol); + PyModule_AddObject(module_obj,"_s_float",(PyObject *)pySymbol_float); + PyModule_AddObject(module_obj,"_s_int",(PyObject *)pySymbol_int); + + // add samplebuffer type + initsamplebuffer(); + PyModule_AddObject(module_obj,"Buffer",(PyObject *)&pySamplebuffer_Type); + + // add message bundle type + initbundle(); + PyModule_AddObject(module_obj,"Bundle",(PyObject *)&pyBundle_Type); + + // ------------------------------------------------------------- + + FLEXT_SETUP(pyobj); + FLEXT_SETUP(pymeth); + FLEXT_SETUP(pyext); +#ifndef PY_NODSP + FLEXT_DSP_SETUP(pydsp); +#endif + +#ifdef FLEXT_THREADS + // release global lock + PyEval_ReleaseLock(); + + // launch thread worker + LaunchThread(quworker,NULL); + + // launch python worker + LaunchThread(pyworker,NULL); +#endif + + post("------------------------------------------------"); + post(""); +} + +FLEXT_LIB_SETUP(py,pybase::lib_setup) + + +// ----------------------------------------------------------------------------------------------------------- + + +pybase::pybase() + : module(NULL) + , dict(NULL) +#ifdef FLEXT_THREADS + , thrcount(0) + , shouldexit(false),stoptick(0) +#endif + , detach(0) + , pymsg(false) +{ + ThrState state = PyLock(); + Py_INCREF(module_obj); + PyUnlock(state); +} + +pybase::~pybase() +{ + ThrState state = PyLock(); + Py_XDECREF(module_obj); + PyUnlock(state); +} + +void pybase::Exit() +{ +#ifdef FLEXT_THREADS + erasethreads(); + + shouldexit = true; + qucond.Signal(); + + if(thrcount) { + // Wait for a certain time + for(int i = 0; i < (PY_STOP_WAIT/PY_STOP_TICK) && thrcount; ++i) + Sleep(PY_STOP_TICK*0.001f); + if(thrcount) { + // Wait forever + post("py/pyext - Waiting for thread termination!"); + while(thrcount) Sleep(PY_STOP_TICK*0.001f); + post("py/pyext - Okay, all threads have terminated"); + } + } +#endif +} + +void pybase::GetDir(PyObject *obj,AtomList &lst) +{ + if(obj) { + ThrState state = PyLock(); + + PyObject *pvar = PyObject_Dir(obj); + if(!pvar) + 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); + } + + PyUnlock(state); + } +} + +void pybase::m__dir(PyObject *obj) +{ + AtomList lst; + GetDir(obj,lst); + // dump dir to attribute outlet + DumpOut(NULL,lst.Count(),lst.Atoms()); +} + +void pybase::m__doc(PyObject *obj) +{ + if(obj) { + ThrState state = PyLock(); + + PyObject *docf = PyDict_GetItemString(obj,"__doc__"); // borrowed!!! + if(docf && PyString_Check(docf)) { + post(""); + const char *s = PyString_AS_STRING(docf); + + // FIX: Python doc strings can easily be larger than 1k characters + // -> split into separate lines + for(;;) { + char buf[1024]; + char *nl = strchr((char *)s,'\n'); // the cast is for Borland C++ + if(!nl) { + // no more newline found + post(s); + break; + } + else { + // copy string before newline to temp buffer and post + unsigned int l = nl-s; + if(l >= sizeof(buf)) l = sizeof buf-1; + strncpy(buf,s,l); // copy all but newline + buf[l] = 0; + post(buf); + s = nl+1; // set after newline + } + } + } + + PyUnlock(state); + } +} + +void pybase::OpenEditor() +{ + if(!module) return; + const char *mname = PyModule_GetFilename(module); + if(!mname) { + PyErr_Clear(); + return; + } + + char fname[1024]; + strcpy(fname,mname); + + // replacing .pyc or .pyo for source file name + char *dt = strrchr(fname,'.'); + if(dt && !strncmp(dt,".py",2)) strcpy(dt,".py"); + + // this should open the editor.... +#if FLEXT_OS == FLEXT_OS_WIN + int err = (int)ShellExecute(NULL,"edit",fname,NULL,NULL,SW_SHOW); + if(err == SE_ERR_NOASSOC) { + // no association found - try notepad + err = (int)ShellExecute(NULL,NULL,"notepad.exe",fname,NULL,SW_SHOW); + } + else if(err == ERROR_FILE_NOT_FOUND || err == SE_ERR_FNF) + post("py/pyext - File not %s found",fname); + else if(err <= 32) + post("py/pyext - Unknown error opening %s",fname); + +#elif FLEXT_OS == FLEXT_OS_MAC + FSRef ref; + OSStatus err = FSPathMakeRef((unsigned char *)fname,&ref,NULL); + if(err) + post("py/pyext - Error interpreting path %s",fname); + else { + FSRef editor; + err = LSGetApplicationForItem(&ref,kLSRolesEditor,&editor,NULL); + if(err) { + // Can't find associated application... try Textedit + err = FSPathMakeRef((unsigned char *)"/Applications/TextEdit.app",&editor,NULL); + if(err) + post("py/pyext - Can't find Textedit application"); + } + + if(!err) { + LSLaunchFSRefSpec lspec; + lspec.appRef = &editor; + lspec.numDocs = 1; + lspec.itemRefs = &ref; + lspec.passThruParams = NULL; + lspec.launchFlags = kLSLaunchDefaults; + lspec.asyncRefCon = NULL; + err = LSOpenFromRefSpec(&lspec,NULL); + if(err) + post("py/pyext - Couldn't launch editor"); + } + } +#else + // thanks to Tim Blechmann + + char *editor = getenv("EDITOR"); + + if(!editor) { // || !strcmp(editor, "/usr/bin/nano") || !strcmp(editor, "/usr/bin/pico") || !strcmp(editor, "/usr/bin/vi")) { + // no environment variable or console text editor found ... use idle instead (should have come with Python) + editor = "idle"; + } + + pid_t child = fork(); + if(!child) { + char cmd[80]; + strcpy(cmd,editor); + strcat(cmd," "); + strcat(cmd,fname); + execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); + } +#endif +} + +void pybase::SetArgs() +{ + // script arguments + int argc = args.Count(); + const t_atom *argv = args.Atoms(); + char **sargv = new char *[argc+1]; + for(int i = 0; i <= argc; ++i) { + sargv[i] = new char[256]; + if(!i) + strcpy(sargv[i],"py/pyext"); + else + GetAString(argv[i-1],sargv[i],255); + } + + // the arguments to the module are only recognized once! (at first use in a patcher) + PySys_SetArgv(argc+1,sargv); + + for(int j = 0; j <= argc; ++j) delete[] sargv[j]; + delete[] sargv; +} + +static bool getmodulesub(const char *mod,char *dir,int len,char *ext) +{ +#if FLEXT_SYS == FLEXT_SYS_PD + char *name; + int fd = open_via_path("",mod,ext,dir,&name,len,0); + if(fd > 0) { + FLEXT_ASSERT(name && *name); + close(fd); + } + else { + // look for mod/__init__.py + std::string tmp(mod); + int l = tmp.size(); + tmp += "/__init__"; + fd = open_via_path("",tmp.c_str(),ext,dir,&name,len,0); + if(fd > 0) { + FLEXT_ASSERT(name && *name); + close(fd); + // we must remove the module name from dir + char *t = dir+strlen(dir)-l; + FLEXT_ASSERT(!strcmp(mod,t) && t[-1] == '/'); + t[-1] = 0; + } + else + name = NULL; + } + + // if dir is current working directory... name points to dir + if(dir == name) strcpy(dir,"."); + return name != NULL; +#elif FLEXT_SYS == FLEXT_SYS_MAX + short path; + long type; + char smod[1024]; + strcpy(smod,mod); + strcat(smod,ext); + bool ok = !locatefile_extended(smod,&path,&type,&type,0); + if(ok) + // convert pathname to unix style + path_topathname(path,NULL,smod); + else { + // do path/file.ext combinations work at all under Max? + strcpy(smod,mod); + + short path; + type = 'fold'; + ok = !locatefile_extended(smod,&path,&type,&type,1); + if(ok) { + // convert pathname to unix style (including trailing slash) + path_topathname(path,NULL,smod); + char *end = smod+strlen(smod); + strcpy(end,mod); + strcat(end,"/__init__"); + strcat(end,ext); + + // check if file is really existing: try to open it + FILE *f = fopen(smod,"r"); + if(f) { + *end = 0; // clear module part ... we only need base path + fclose(f); + } + else + ok = false; + } + } + + if(ok) { + // convert path into slash style needed for Python +#if 0 + // Max API function uses Volume:/Path notation + path_nameconform(smod,dir,PATH_STYLE_SLASH,PATH_TYPE_ABSOLUTE); +#else +#if FLEXT_OS == FLEXT_OS_WIN + char *colon = NULL; +#else + char *colon = strchr(smod,':'); +#endif + if(colon) { + *colon = 0; + strcpy(dir,"/Volumes/"); + strcat(dir,smod); + strcat(dir,colon+1); + } + else + strcpy(dir,smod); +#endif + return true; + } + else + // not found + return false; +#else +#pragma message("Not implemented"); + return false; +#endif +} + +static bool getmodulepath(const char *mod,char *dir,int len) +{ + return + getmodulesub(mod,dir,len,".py") || + getmodulesub(mod,dir,len,".pyc") || + getmodulesub(mod,dir,len,".pyo"); +} + +bool pybase::ImportModule(const char *name) +{ + if(name) { + if(modname == name) { + // module with the same name is already loaded + if(module) return true; + } + else + modname = name; + } + else + modname.clear(); + + UnimportModule(); + return ReloadModule(); +} + +void pybase::UnimportModule() +{ + if(module) { + FLEXT_ASSERT(dict && module_obj && module_dict); + + Py_DECREF(module); + + // reference count to module is not 0 here, altough probably the last instance was unloaded + // Python retains one reference to the module all the time + // we don't care + + module = NULL; + dict = NULL; + } +} + +bool pybase::ReloadModule() +{ + SetArgs(); + PyObject *newmod; + + if(modname.length()) { + + if(module) + newmod = PyImport_ReloadModule(module); + else { + // search in module path (TODO: check before if module is already present to avoid costly searching) + char dir[1024]; + if(!getmodulepath(modname.c_str(),dir,sizeof(dir))) + PyErr_SetString(PyExc_ImportError,"Module not found in path"); + else + AddToPath(dir); + + // module could also be loaded ok, even if it's not in the path (e.g. for internal stuff) + newmod = 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 + UnimportModule(); + return false; + } + else { + Py_XDECREF(module); + module = newmod; + dict = PyModule_GetDict(module); // borrowed + return true; + } +} + +void pybase::AddToPath(const char *dir) +{ + if(dir && *dir) { + PyObject *pobj = PySys_GetObject("path"); + if(pobj && PyList_Check(pobj)) { + PyObject *ps = PyString_FromString(dir); + if(!PySequence_Contains(pobj,ps)) + PyList_Append(pobj,ps); // makes new reference + Py_DECREF(ps); + } + PySys_SetObject("path",pobj); // steals reference to pobj + } +} + +void pybase::AddCurrentPath(flext_base *o) +{ + char dir[1024]; + + // add dir of current patch to path + o->GetCanvasDir(dir,sizeof(dir)); + if(*dir) AddToPath(dir); + + // add current dir to path +#if FLEXT_SYS == FLEXT_SYS_PD + AddToPath(GetString(canvas_getcurrentdir())); +#elif FLEXT_SYS == FLEXT_SYS_MAX + short path = path_getdefault(); + path_topathname(path,NULL,dir); + AddToPath(dir); +#endif +} + +bool pybase::OutObject(flext_base *ext,int o,PyObject *obj) +{ + flext::AtomListStatic<16> lst; + const t_symbol *sym = pymsg?GetPyAtom(lst,obj):GetPyArgs(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; + } + else + return false; +} + +void pybase::Reload() +{ + ThrState state = PyLock(); + + 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; + +// post to the console +PyObject* pybase::StdOut_Write(PyObject* self, PyObject* args) +{ + // should always be a tuple + FLEXT_ASSERT(PyTuple_Check(args)); + + const int sz = PyTuple_GET_SIZE(args); + + for(int i = 0; i < sz; ++i) { + PyObject *val = PyTuple_GET_ITEM(args,i); // borrowed reference + PyObject *str = PyObject_Str(val); // new reference + char *cstr = PyString_AS_STRING(str); + char *lf = strchr(cstr,'\n'); + + // line feed in string + if(!lf) { + // no -> just append + if(output) + PyString_ConcatAndDel(&output,str); // str is decrefd + else + output = str; // take str reference + } + else { + // yes -> append up to line feed, reset output buffer to string remainder + PyObject *part = PyString_FromStringAndSize(cstr,lf-cstr); // new reference + if(output) + PyString_ConcatAndDel(&output,part); // str is decrefd + else + output = part; // take str reference + + // output concatenated string + post(PyString_AS_STRING(output)); + + Py_DECREF(output); + output = PyString_FromString(lf+1); // new reference + } + } + + Py_INCREF(Py_None); + return Py_None; +} + + +class work_data +{ +public: + work_data(PyObject *f,PyObject *a): fun(f),args(a) {} + ~work_data() { Py_DECREF(fun); Py_DECREF(args); } + + PyObject *fun,*args; +}; + +bool pybase::gencall(PyObject *pmeth,PyObject *pargs) +{ + bool ret = false; + + // Now call method + switch(detach) { + case 0: + ret = docall(pmeth,pargs); + Py_DECREF(pargs); + Py_DECREF(pmeth); + break; +#ifdef FLEXT_THREADS + case 1: + // put call into queue + ret = qucall(pmeth,pargs); + break; + case 2: + // each call a new thread + if(!shouldexit) { + thr_params *p = new thr_params; + p->cl = (flext_base *)this; + p->var->_ext = new work_data(pmeth,pargs); + ret = LaunchThread(thrworker,p); + if(!ret) post("py/pyext - Failed to launch thread!"); + } + break; +#endif + default: + post("py/pyext - Unknown detach mode"); + } + return ret; +} + +void pybase::exchandle() +{ +#if 0 + // want to use that, but exception keeps a reference to the object + // might be a Python bug! + PyErr_Print(); +#else + // must use that instead... clear the exception + PyObject *type,*value,*traceback; + PyErr_Fetch(&type,&value,&traceback); + PyErr_NormalizeException(&type,&value,&traceback); + PyErr_Display(type,value,traceback); + + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); +#endif +} + +#ifdef FLEXT_THREADS +void pybase::thrworker(thr_params *p) +{ + FLEXT_ASSERT(p); + pybase *th = (pybase *)p->cl; + work_data *w = (work_data *)p->var->_ext; + + ++th->thrcount; // \todo this should be atomic + ThrState state = PyLock(); + + // call worker + th->docall(w->fun,w->args); + delete w; + + PyUnlock(state); + --th->thrcount; // \todo this should be atomic +} + +/*! This thread function basically keeps alive the Python interpreter in the background + It's good for threads that have been started from scripted functions +*/ +void pybase::pyworker(thr_params *) +{ + ThrState state = PyLock(); + + PyObject *timemod = PyImport_ImportModule("time"); + PyObject *sleep = PyObject_GetAttrString(timemod,"sleep"); + PyObject *args = PyTuple_New(1); + PyTuple_SET_ITEM(args,0,PyFloat_FromDouble(1000000)); + + for(;;) { + PyObject *res = PyObject_CallObject(sleep,args); + Py_DECREF(res); + } + + PyUnlock(state); +} + +void pybase::quworker(thr_params *) +{ + FifoEl *el; + ThrState my = FindThreadState(),state; + + for(;;) { + while(el = qufifo.Get()) { + ++el->th->thrcount; // \todo this should be atomic + state = PyLock(my); + el->th->docall(el->fun,el->args); + Py_XDECREF(el->fun); + Py_XDECREF(el->args); + PyUnlock(state); + --el->th->thrcount; // \todo this should be atomic + qufifo.Free(el); + } + qucond.Wait(); + } + + // we never end +#if 0 + state = PyLock(my); + // unref remaining Python objects + while(el = qufifo.Get()) { + Py_XDECREF(el->fun); + Py_XDECREF(el->args); + qufifo.Free(el); + } + PyUnlock(state); +#endif +} + +void pybase::erasethreads() +{ + PyFifo tmp; + FifoEl *el; + while(el = qufifo.Get()) { + if(el->th == this) { + Py_XDECREF(el->fun); + Py_XDECREF(el->args); + qufifo.Free(el); + } + else + tmp.Put(el); + } + // Push back + while(el = tmp.Get()) qufifo.Put(el); +} +#endif + +bool pybase::collect() +{ + if(gcollect) { + PyObject *ret = PyObject_CallObject(gcollect,NULL); + if(ret) { +#ifdef FLEXT_DEBUG + int refs = PyInt_AsLong(ret); + if(refs) post("py/pyext - Garbage collector reports %i unreachable objects",refs); +#endif + Py_DECREF(ret); + return false; + } + } + return true; +} diff --git a/externals/grill/py/source/pybase.h b/externals/grill/py/source/pybase.h index b5cc8220..61518a2a 100644 --- a/externals/grill/py/source/pybase.h +++ b/externals/grill/py/source/pybase.h @@ -1,228 +1,251 @@ -/*
-
-py/pyext - python script object for PD and MaxMSP
-
-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.
-
-*/
-
-#ifndef __PYBASE_H
-#define __PYBASE_H
-
-#include "main.h"
-#include "pysymbol.h"
-#include "pybuffer.h"
-#include "pybundle.h"
-
-class pybase
- : public flext
-{
-public:
- pybase();
- virtual ~pybase();
-
- void Exit();
-
- 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();
-
-protected:
-
- virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv) = 0;
-
- void m__dir(PyObject *obj);
- void m__doc(PyObject *obj);
-
- void m_dir() { m__dir(module); }
- void mg_dir(AtomList &lst) { m__dir(module); }
- void m_doc() { m__doc(dict); }
-
- std::string modname; // module name
- PyObject *module,*dict; // object module and associated dictionary
-
- static const char *py_doc;
-
- void GetDir(PyObject *obj,AtomList &lst);
-
- AtomList args;
-
- void AddCurrentPath(flext_base *o);
- void SetArgs();
-
- bool OutObject(flext_base *ext,int o,PyObject *obj);
-
- // reload module and all connected objects
- void Reload();
-
- bool ImportModule(const char *name);
- void UnimportModule();
- bool ReloadModule();
-
- // 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)
- {
- if(respond) {
- t_atom a;
- SetBool(a,b);
- DumpOut(sym_response,1,&a);
- }
- }
-
- void Report() { while(PyErr_Occurred()) PyErr_Print(); }
-
- static bool IsAnything(const t_symbol *s) { return s && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; }
- static bool IsAtom(const t_symbol *s) { return s == sym_float || s == sym_int || s == sym_symbol || s == sym_pointer; }
-
-// enum retval { nothing,atom,sequ };
-
- // --- 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);
- static PyObject *py_send(PyObject *,PyObject *args);
-#ifdef FLEXT_THREADS
- static PyObject *py_priority(PyObject *,PyObject *args);
-#endif
-
- static PyObject *py_arraysupport(PyObject *,PyObject *args);
- static PyObject *py_samplerate(PyObject *,PyObject *args);
- static PyObject *py_blocksize(PyObject *,PyObject *args);
-
-#if FLEXT_SYS == FLEXT_SYS_PD
- static PyObject *py_getvalue(PyObject *,PyObject *args);
- static PyObject *py_setvalue(PyObject *,PyObject *args);
-#endif
-
- static PyObject *py_list(PyObject *,PyObject *args);
- static PyObject *py_tuple(PyObject *,PyObject *args);
-
- // ----thread stuff ------------
-
- virtual void m_stop(int argc,const t_atom *argv);
-
- bool respond;
-#ifdef FLEXT_THREADS
- int thrcount;
- bool shouldexit;
- int stoptick;
- Timer stoptmr;
-
- void tick(void *);
-#endif
-
- int detach;
- bool pymsg;
-
- bool gencall(PyObject *fun,PyObject *args);
-
- bool docall(PyObject *fun,PyObject *args)
- {
- callpy(fun,args);
- if(PyErr_Occurred()) {
- exchandle();
- return false;
- }
- else
- return true;
- }
-
- virtual void callpy(PyObject *fun,PyObject *args) = 0;
-
- void exchandle();
-
- static bool collect();
-
-protected:
-
-#ifdef FLEXT_THREADS
- static void thrworker(thr_params *data);
-
- bool qucall(PyObject *fun,PyObject *args)
- {
- FifoEl *el = qufifo.New();
- el->Set(this,fun,args);
- qufifo.Put(el);
- qucond.Signal();
- return true;
- }
-
- static void quworker(thr_params *);
- void erasethreads();
-
- static PyFifo qufifo;
- static ThrCond qucond;
- static PyThreadState *pythrsys;
-#endif
-
- static const t_symbol *sym_fint; // float or int symbol, depending on native number message type
- static const t_symbol *sym_response;
-
- static const t_symbol *getone(t_atom &at,PyObject *arg);
- static const t_symbol *getlist(t_atom *lst,PyObject *seq,int cnt,int offs = 0);
-
-public:
-
- static void AddToPath(const char *dir);
-
-#ifdef FLEXT_THREADS
- static PyThreadState *FindThreadState();
- static void FreeThreadState();
-
- // this is especially needed when one py/pyext object calls another one
- // we don't want the message to be queued, but otoh we have to avoid deadlock
- // (recursive calls can only happen in the system thread)
- static int lockcount;
-
- static PyThreadState *PyLock(PyThreadState *st = FindThreadState())
- {
- if(!IsSystemThread() || !lockcount++) PyEval_AcquireLock();
- return PyThreadState_Swap(st);
- }
-
- static PyThreadState *PyLockSys()
- {
- if(!lockcount++) PyEval_AcquireLock();
- return PyThreadState_Swap(pythrsys);
- }
-
- static void PyUnlock(PyThreadState *st)
- {
- PyThreadState *old = PyThreadState_Swap(st);
- if(old != pythrsys || !--lockcount) PyEval_ReleaseLock();
- }
-#else
- static PyThreadState *PyLock(PyThreadState * = NULL) { return NULL; }
- static PyThreadState *PyLockSys() { return NULL; }
- static void PyUnlock(PyThreadState *st) {}
-#endif
-
- static PyObject* StdOut_Write(PyObject* Self, PyObject* Args);
-};
-
-#endif
+/* + +py/pyext - python script object for PD and MaxMSP + +Copyright (c)2002-2007 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. + +*/ + +#ifndef __PYBASE_H +#define __PYBASE_H + +#include "main.h" +#include "pysymbol.h" +#include "pybuffer.h" +#include "pybundle.h" + +#ifdef PY_USE_GIL + typedef PyGILState_STATE ThrState; +#else + typedef PyThreadState *ThrState; +#endif + +class pybase + : public flext +{ +public: + pybase(); + virtual ~pybase(); + + void Exit(); + + 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(); + +protected: + + virtual void DumpOut(const t_symbol *sym,int argc,const t_atom *argv) = 0; + + void m__dir(PyObject *obj); + void m__doc(PyObject *obj); + + void m_dir() { m__dir(module); } + void mg_dir(AtomList &lst) { m__dir(module); } + void m_doc() { m__doc(dict); } + + std::string modname; // module name + PyObject *module,*dict; // object module and associated dictionary + + static const char *py_doc; + + void GetDir(PyObject *obj,AtomList &lst); + + AtomList args; + + void AddCurrentPath(flext_base *o); + void SetArgs(); + + bool OutObject(flext_base *ext,int o,PyObject *obj); + + // reload module and all connected objects + void Reload(); + + bool ImportModule(const char *name); + void UnimportModule(); + bool ReloadModule(); + + // 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) + { + if(respond) { + t_atom a; + SetBool(a,b); + DumpOut(sym_response,1,&a); + } + } + + void Report() { while(PyErr_Occurred()) PyErr_Print(); } + + static bool IsAnything(const t_symbol *s) { return s && s != sym_float && s != sym_int && s != sym_symbol && s != sym_list && s != sym_pointer; } + static bool IsAtom(const t_symbol *s) { return s == sym_float || s == sym_int || s == sym_symbol || s == sym_pointer; } + +// enum retval { nothing,atom,sequ }; + + // --- 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); + static PyObject *py_send(PyObject *,PyObject *args); +#ifdef FLEXT_THREADS + static PyObject *py_priority(PyObject *,PyObject *args); +#endif + + static PyObject *py_arraysupport(PyObject *,PyObject *args); + static PyObject *py_samplerate(PyObject *,PyObject *args); + static PyObject *py_blocksize(PyObject *,PyObject *args); + +#if FLEXT_SYS == FLEXT_SYS_PD + static PyObject *py_getvalue(PyObject *,PyObject *args); + static PyObject *py_setvalue(PyObject *,PyObject *args); +#endif + + static PyObject *py_list(PyObject *,PyObject *args); + static PyObject *py_tuple(PyObject *,PyObject *args); + + // ----thread stuff ------------ + + virtual void m_stop(int argc,const t_atom *argv); + + bool respond; +#ifdef FLEXT_THREADS + int thrcount; + bool shouldexit; + int stoptick; + Timer stoptmr; + + void tick(void *); +#endif + + int detach; + bool pymsg; + + bool gencall(PyObject *fun,PyObject *args); + + bool docall(PyObject *fun,PyObject *args) + { + callpy(fun,args); + if(PyErr_Occurred()) { + exchandle(); + return false; + } + else + return true; + } + + virtual void callpy(PyObject *fun,PyObject *args) = 0; + + void exchandle(); + + static bool collect(); + +protected: + +#ifdef FLEXT_THREADS + static void thrworker(thr_params *data); + + bool qucall(PyObject *fun,PyObject *args) + { + FifoEl *el = qufifo.New(); + el->Set(this,fun,args); + qufifo.Put(el); + qucond.Signal(); + return true; + } + + static void quworker(thr_params *); + static void pyworker(thr_params *); + void erasethreads(); + + static PyFifo qufifo; + static ThrCond qucond; + +#ifndef PY_USE_GIL + static ThrState pythrsys; +#endif +#endif + + static const t_symbol *sym_fint; // float or int symbol, depending on native number message type + static const t_symbol *sym_response; + + static const t_symbol *getone(t_atom &at,PyObject *arg); + static const t_symbol *getlist(t_atom *lst,PyObject *seq,int cnt,int offs = 0); + +public: + + static void AddToPath(const char *dir); + +#ifdef FLEXT_THREADS + // this is especially needed when one py/pyext object calls another one + // we don't want the message to be queued, but otoh we have to avoid deadlock + // (recursive calls can only happen in the system thread) + static int lockcount; + +#ifdef PY_USE_GIL + static inline ThrState FindThreadState() { return ThrState(); } + + static inline ThrState PyLock(ThrState = ThrState()) { return PyGILState_Ensure(); } + static inline ThrState PyLockSys() { return PyLock(); } + static inline void PyUnlock(ThrState st) { PyGILState_Release(st); } +#else // PY_USE_GIL + static ThrState FindThreadState(); + static void FreeThreadState(); + + static ThrState PyLock(ThrState st = FindThreadState()) + { + if(!IsSystemThread() || !lockcount++) PyEval_AcquireLock(); + return PyThreadState_Swap(st); + } + +#if 1 + static inline ThrState PyLockSys() { return PyLock(); } +#else + static ThrState PyLockSys() + { + if(!lockcount++) PyEval_AcquireLock(); + return PyThreadState_Swap(pythrsys); + } +#endif + + static void PyUnlock(ThrState st) + { + ThrState old = PyThreadState_Swap(st); + if(old != pythrsys || !--lockcount) PyEval_ReleaseLock(); + } +#endif // PY_USE_GIL + +#else // FLEXT_THREADS + static inline ThrState PyLock(ThrState = NULL) { return NULL; } + static inline ThrState PyLockSys() { return NULL; } + static inline void PyUnlock(ThrState st) {} +#endif + + static PyObject* StdOut_Write(PyObject* Self, PyObject* Args); +}; + +#endif diff --git a/externals/grill/py/source/pybundle.cpp b/externals/grill/py/source/pybundle.cpp index 69f5d90c..ee2e16c0 100644 --- a/externals/grill/py/source/pybundle.cpp +++ b/externals/grill/py/source/pybundle.cpp @@ -1,232 +1,232 @@ -/*
-
-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 "pyprefix.h"
-#include "pybundle.h"
-#include "pyext.h"
-
-static PyObject *bundle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- pyBundle *self = (pyBundle *)pyBundle_Type.tp_alloc(&pyBundle_Type, 0);
- if(self) self->bundle = flext::MsgNew();
- return (PyObject *)self;
-}
-
-static int bundle_init(PyObject *self, PyObject *args, PyObject *kwds)
-{
- FLEXT_ASSERT(pyBundle_Check(self));
-
- int len = PySequence_Length(args);
- if(len) {
- PyErr_SetString(PyExc_TypeError,"no arguments expected");
- return -1;
- }
-
- return 0;
-}
-
-static void bundle_dealloc(PyObject *obj)
-{
- pyBundle *self = (pyBundle *)obj;
- if(self->bundle) flext::MsgFree(self->bundle);
- obj->ob_type->tp_free(obj);
-}
-
-static PyObject *bundle_send(PyObject *obj)
-{
- pyBundle *self = (pyBundle *)obj;
- if(self->bundle) {
- flext::ToOutMsg(self->bundle);
- self->bundle = NULL;
-
- Py_INCREF(obj);
- return obj;
- }
- else {
- PyErr_SetString(PyExc_RuntimeError,"already sent");
- return NULL;
- }
-}
-
-static PyObject *bundle_repr(PyObject *self)
-{
- FLEXT_ASSERT(pyBundle_Check(self));
- return (PyObject *)PyString_FromFormat("<Bundle %p>",pyBundle_AS_BUNDLE(self));
-}
-
-static PyObject *bundle_str(PyObject *self)
-{
- return bundle_repr(self);
-}
-
-static PyObject *bundle_richcompare(PyObject *a,PyObject *b,int cmp)
-{
- if(pyBundle_Check(a) && pyBundle_Check(b)) {
- const flext::MsgBundle *abnd = pyBundle_AS_BUNDLE(a);
- const flext::MsgBundle *bbnd = pyBundle_AS_BUNDLE(b);
- bool ret;
- switch(cmp) {
- case Py_LT: ret = abnd < bbnd; break;
- case Py_LE: ret = abnd <= bbnd; break;
- case Py_EQ: ret = abnd == bbnd; break;
- case Py_NE: ret = abnd != bbnd; break;
- case Py_GT: ret = abnd > bbnd; break;
- case Py_GE: ret = abnd >= bbnd; break;
- }
- return PyBool_FromLong(ret);
- }
+/* + +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 "pyprefix.h" +#include "pybundle.h" +#include "pyext.h" + +static PyObject *bundle_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + pyBundle *self = (pyBundle *)pyBundle_Type.tp_alloc(&pyBundle_Type, 0); + if(self) self->bundle = flext::MsgNew(); + return (PyObject *)self; +} + +static int bundle_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + FLEXT_ASSERT(pyBundle_Check(self)); + + int len = PySequence_Length(args); + if(len) { + PyErr_SetString(PyExc_TypeError,"no arguments expected"); + return -1; + } + + return 0; +} + +static void bundle_dealloc(PyObject *obj) +{ + pyBundle *self = (pyBundle *)obj; + if(self->bundle) flext::MsgFree(self->bundle); + obj->ob_type->tp_free(obj); +} + +static PyObject *bundle_send(PyObject *obj) +{ + pyBundle *self = (pyBundle *)obj; + if(self->bundle) { + flext::ToOutMsg(self->bundle); + self->bundle = NULL; + + Py_INCREF(obj); + return obj; + } + else { + PyErr_SetString(PyExc_RuntimeError,"already sent"); + return NULL; + } +} + +static PyObject *bundle_repr(PyObject *self) +{ + FLEXT_ASSERT(pyBundle_Check(self)); + return (PyObject *)PyString_FromFormat("<Bundle %p>",pyBundle_AS_BUNDLE(self)); +} + +static PyObject *bundle_str(PyObject *self) +{ + return bundle_repr(self); +} + +static PyObject *bundle_richcompare(PyObject *a,PyObject *b,int cmp) +{ + if(pyBundle_Check(a) && pyBundle_Check(b)) { + const flext::MsgBundle *abnd = pyBundle_AS_BUNDLE(a); + const flext::MsgBundle *bbnd = pyBundle_AS_BUNDLE(b); + bool ret; + switch(cmp) { + case Py_LT: ret = abnd < bbnd; break; + case Py_LE: ret = abnd <= bbnd; break; + case Py_EQ: ret = abnd == bbnd; break; + case Py_NE: ret = abnd != bbnd; break; + case Py_GT: ret = abnd > bbnd; break; + case Py_GE: ret = abnd >= bbnd; break; + } + return PyBool_FromLong(ret); + } Py_INCREF(Py_NotImplemented); return Py_NotImplemented; -}
-
-static long bundle_hash(PyObject *self)
-{
- FLEXT_ASSERT(pyBundle_Check(self));
- return (long)pyBundle_AS_BUNDLE(self);
-}
-
-
-static PyObject *bundle_append(PyObject *self,PyObject *args)
-{
- flext::MsgBundle *b = pyBundle_AS_BUNDLE(self);
- if(b) {
- int sz = PyTuple_GET_SIZE(args),offs = 0;
- PyObject *tg,*outl;
- pyext *ext = NULL;
- const t_symbol *recv;
- int o;
-
- if(sz > 2 &&
- (tg = PyTuple_GET_ITEM(args,0)) != NULL && PyInstance_Check(tg) &&
- (outl = PyTuple_GET_ITEM(args,1)) != NULL && PyInt_Check(outl)
- ) {
- // Sending to outlet
- ext = pyext::GetThis(tg);
- o = PyInt_AS_LONG(outl);
-
- if(o < 1 || o > ext->Outlets()) {
- PyErr_SetString(PyExc_ValueError,"Outlet index out of range");
- return NULL;
- }
-
- offs += 2;
- }
- else if(sz > 1 &&
- (tg = PyTuple_GET_ITEM(args,0)) != NULL && (recv = pyObject_AsSymbol(tg)) != NULL
- ) {
- // Sending to receiver
- offs++;
- }
- else {
- // not recognized
- PyErr_SetString(PyExc_SyntaxError,"Unrecognized arguments");
- return NULL;
- }
-
- PyObject *val;
- if(sz-offs == 1) {
- val = PyTuple_GET_ITEM(args,offs); // borrow reference
- Py_INCREF(val);
- }
- else
- val = PyTuple_GetSlice(args,offs,sz); // new ref
-
- flext::AtomListStatic<16> lst;
- const t_symbol *sym = pybase::GetPyArgs(lst,val);
- Py_DECREF(val);
-
- if(sym) {
- if(ext) {
- FLEXT_ASSERT(outl);
- ext->MsgAddAnything(b,o-1,sym,lst.Count(),lst.Atoms());
- }
- else {
- FLEXT_ASSERT(sym);
- if(!flext::MsgForward(b,recv,sym,lst.Count(),lst.Atoms())) {
- PyErr_SetString(PyExc_ValueError,"Receiver not found");
- return NULL;
- }
- }
-
- Py_INCREF(Py_None);
- return Py_None;
- }
- else {
- FLEXT_ASSERT(PyErr_Occurred());
- return NULL;
- }
-
- Py_INCREF(self);
- return self;
- }
- else {
- PyErr_SetString(PyExc_RuntimeError,"Invalid bundle");
- return NULL;
- }
-}
-
-static PyMethodDef bundle_methods[] = {
- {"append", (PyCFunction)bundle_append,METH_VARARGS,"Append message to bundle"},
- {"send", (PyCFunction)bundle_send,METH_NOARGS,"Send bundle"},
- {NULL} /* Sentinel */
-};
-
-
-
-PyTypeObject pyBundle_Type = {
- PyObject_HEAD_INIT(NULL)
- 0, /*ob_size*/
- "Bundle", /*tp_name*/
- sizeof(pyBundle), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- bundle_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- bundle_repr, /*tp_repr*/
- 0, /*tp_as_number*/
- 0, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- bundle_hash, /*tp_hash */
- 0, /*tp_call*/
- bundle_str, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/, /*tp_flags*/
- "Bundle objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- bundle_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- bundle_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- bundle_init, /* tp_init */
- 0, /* tp_alloc */
- bundle_new, /* tp_new */
-};
-
-
-void initbundle()
-{
- if(PyType_Ready(&pyBundle_Type) < 0)
- FLEXT_ASSERT(false);
- else
- Py_INCREF(&pyBundle_Type);
-}
+} + +static long bundle_hash(PyObject *self) +{ + FLEXT_ASSERT(pyBundle_Check(self)); + return (long)pyBundle_AS_BUNDLE(self); +} + + +static PyObject *bundle_append(PyObject *self,PyObject *args) +{ + flext::MsgBundle *b = pyBundle_AS_BUNDLE(self); + if(b) { + int sz = PyTuple_GET_SIZE(args),offs = 0; + PyObject *tg,*outl; + pyext *ext = NULL; + const t_symbol *recv; + int o; + + if(sz > 2 && + (tg = PyTuple_GET_ITEM(args,0)) != NULL && PyInstance_Check(tg) && + (outl = PyTuple_GET_ITEM(args,1)) != NULL && PyInt_Check(outl) + ) { + // Sending to outlet + ext = pyext::GetThis(tg); + o = PyInt_AS_LONG(outl); + + if(o < 1 || o > ext->Outlets()) { + PyErr_SetString(PyExc_ValueError,"Outlet index out of range"); + return NULL; + } + + offs += 2; + } + else if(sz > 1 && + (tg = PyTuple_GET_ITEM(args,0)) != NULL && (recv = pyObject_AsSymbol(tg)) != NULL + ) { + // Sending to receiver + offs++; + } + else { + // not recognized + PyErr_SetString(PyExc_SyntaxError,"Unrecognized arguments"); + return NULL; + } + + PyObject *val; + if(sz-offs == 1) { + val = PyTuple_GET_ITEM(args,offs); // borrow reference + Py_INCREF(val); + } + else + val = PyTuple_GetSlice(args,offs,sz); // new ref + + flext::AtomListStatic<16> lst; + const t_symbol *sym = pybase::GetPyArgs(lst,val); + Py_DECREF(val); + + if(sym) { + if(ext) { + FLEXT_ASSERT(outl); + ext->MsgAddAnything(b,o-1,sym,lst.Count(),lst.Atoms()); + } + else { + FLEXT_ASSERT(sym); + if(!flext::MsgForward(b,recv,sym,lst.Count(),lst.Atoms())) { + PyErr_SetString(PyExc_ValueError,"Receiver not found"); + return NULL; + } + } + + Py_INCREF(Py_None); + return Py_None; + } + else { + FLEXT_ASSERT(PyErr_Occurred()); + return NULL; + } + + Py_INCREF(self); + return self; + } + else { + PyErr_SetString(PyExc_RuntimeError,"Invalid bundle"); + return NULL; + } +} + +static PyMethodDef bundle_methods[] = { + {"append", (PyCFunction)bundle_append,METH_VARARGS,"Append message to bundle"}, + {"send", (PyCFunction)bundle_send,METH_NOARGS,"Send bundle"}, + {NULL} /* Sentinel */ +}; + + + +PyTypeObject pyBundle_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "Bundle", /*tp_name*/ + sizeof(pyBundle), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + bundle_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + bundle_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + bundle_hash, /*tp_hash */ + 0, /*tp_call*/ + bundle_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/, /*tp_flags*/ + "Bundle objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + bundle_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + bundle_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + bundle_init, /* tp_init */ + 0, /* tp_alloc */ + bundle_new, /* tp_new */ +}; + + +void initbundle() +{ + if(PyType_Ready(&pyBundle_Type) < 0) + FLEXT_ASSERT(false); + else + Py_INCREF(&pyBundle_Type); +} diff --git a/externals/grill/py/source/pybundle.h b/externals/grill/py/source/pybundle.h index 5978cc38..1e840eb5 100644 --- a/externals/grill/py/source/pybundle.h +++ b/externals/grill/py/source/pybundle.h @@ -1,16 +1,16 @@ -/*
-
-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.
-
-*/
-
-#ifndef __PYBUNDLE_H
-#define __PYBUNDLE_H
-
+/* + +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. + +*/ + +#ifndef __PYBUNDLE_H +#define __PYBUNDLE_H + #include <flext.h> #if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500) @@ -33,28 +33,28 @@ WARRANTIES, see the file, "license.txt," in this distribution. #else #define PY_EXPORT #endif -
-typedef struct {
- PyObject_HEAD
- /* Type-specific fields go here. */
- flext::MsgBundle *bundle;
-} pyBundle;
-
-PY_EXPORT extern PyTypeObject pyBundle_Type;
-
+ +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ + flext::MsgBundle *bundle; +} pyBundle; + +PY_EXPORT extern PyTypeObject pyBundle_Type; + #define pyBundle_Check(op) PyObject_TypeCheck(op, &pyBundle_Type) #define pyBundle_CheckExact(op) ((op)->ob_type == &pyBundle_Type) -inline flext::MsgBundle *pyBundle_AS_BUNDLE(PyObject *op)
-{
- return ((pyBundle *)op)->bundle;
-}
-
-inline flext::MsgBundle *pyBundle_AsBundle(PyObject *op)
-{
- return pyBundle_Check(op)?pyBundle_AS_BUNDLE(op):NULL;
-}
-
+inline flext::MsgBundle *pyBundle_AS_BUNDLE(PyObject *op) +{ + return ((pyBundle *)op)->bundle; +} + +inline flext::MsgBundle *pyBundle_AsBundle(PyObject *op) +{ + return pyBundle_Check(op)?pyBundle_AS_BUNDLE(op):NULL; +} -#endif
+ +#endif diff --git a/externals/grill/py/source/pydsp.cpp b/externals/grill/py/source/pydsp.cpp index a88a3956..07fa75af 100644 --- a/externals/grill/py/source/pydsp.cpp +++ b/externals/grill/py/source/pydsp.cpp @@ -1,190 +1,190 @@ -/*
-
-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.
-
-*/
-
-#ifndef PY_NODSP
-
-#include "pyext.h"
-
-class pydsp
- : public pyext
-{
- FLEXT_HEADER(pydsp,pyext)
-public:
- pydsp(int argc,const t_atom *argv);
-
-protected:
- virtual bool CbDsp();
- virtual void CbSignal();
-
- virtual bool DoInit();
- virtual void DoExit();
-
- virtual PyObject *GetSig(int ix,bool in);
-
- void NewBuffers();
- void FreeBuffers();
-
- PyObject *dspfun,*sigfun;
- PyObject **buffers;
-};
-
-FLEXT_LIB_DSP_V("pyext~ pyext.~ pyx~ pyx.~",pydsp)
-
-pydsp::pydsp(int argc,const t_atom *argv)
- : pyext(argc,argv,true)
- , dspfun(NULL),sigfun(NULL)
-{}
-
-bool pydsp::DoInit()
-{
- if(!pyext::DoInit()) return false;
-
- if(pyobj)
- {
- dspfun = PyObject_GetAttrString(pyobj,"_dsp"); // get ref
- if(!dspfun)
- PyErr_Clear();
- else if(!PyMethod_Check(dspfun)) {
- Py_DECREF(dspfun);
- dspfun = NULL;
- }
- }
- return true;
-}
-
-void pydsp::DoExit()
-{
- if(dspfun) { Py_DECREF(dspfun); dspfun = NULL; }
- if(sigfun) { Py_DECREF(sigfun); sigfun = NULL; }
-
- FreeBuffers();
-}
-
-PyObject *arrayfrombuffer(PyObject *buf,int c,int n);
-
-void pydsp::NewBuffers()
-{
- int i,n = Blocksize();
- const int ins = CntInSig(),outs = CntOutSig();
- t_sample *const *insigs = InSig();
- t_sample *const *outsigs = OutSig();
-
- // inlet/outlet count can't change so we don't have to deallocate
- if(!buffers) {
- int cnt = ins+outs;
- buffers = new PyObject *[cnt];
- memset(buffers,0,cnt*sizeof(*buffers));
- }
-
- for(i = 0; i < ins; ++i) {
- Py_XDECREF(buffers[i]);
- PyObject *b = PyBuffer_FromReadWriteMemory(insigs[i],n*sizeof(t_sample));
- buffers[i] = arrayfrombuffer(b,1,n);
- Py_DECREF(b);
- }
- for(i = 0; i < outs; ++i) {
- Py_XDECREF(buffers[ins+i]);
- if(i < ins && outsigs[i] == insigs[i]) {
- // same vectors - share the objects!
- buffers[ins+i] = buffers[i];
- Py_XINCREF(buffers[i]);
- }
- else {
- PyObject *b = PyBuffer_FromReadWriteMemory(outsigs[i],n*sizeof(t_sample));
- buffers[ins+i] = arrayfrombuffer(b,1,n);
- Py_DECREF(b);
- }
- }
-}
-
-void pydsp::FreeBuffers()
-{
- if(buffers) {
- int cnt = CntInSig()+CntOutSig();
- for(int i = 0; i < cnt; ++i) Py_XDECREF(buffers[i]);
- delete[] buffers;
- buffers = NULL;
- }
-}
-
-bool pydsp::CbDsp()
-{
- if(pyobj && (CntInSig() || CntOutSig()))
- {
- PyThreadState *state = PyLockSys();
-
- NewBuffers();
-
- bool dodsp = true;
- if(dspfun) {
- PyObject *ret = PyObject_CallObject(dspfun,NULL);
- if(ret) {
- dodsp = PyObject_IsTrue(ret) != 0;
- Py_DECREF(ret);
- }
- else {
-#ifdef FLEXT_DEBUG
- PyErr_Print();
-#else
- PyErr_Clear();
-#endif
- }
- }
-
- // do that here instead of where dspfun is initialized, so that
- // _signal can be assigned in _dsp
- // optimizations may be done there to assign the right _signal version
- Py_XDECREF(sigfun);
-
- if(dodsp) {
- sigfun = PyObject_GetAttrString(pyobj,"_signal"); // get ref
- if(!sigfun)
- PyErr_Clear();
- else if(!PyMethod_Check(sigfun)) {
- Py_DECREF(sigfun);
- sigfun = NULL;
- }
- }
- else
- sigfun = NULL;
-
- PyUnlock(state);
- return sigfun != NULL;
- }
- else
- // switch on dsp only if there are signal inlets or outlets
- return false;
-}
-
-void pydsp::CbSignal()
-{
- PyThreadState *state = PyLockSys();
- PyObject *ret = PyObject_CallObject(sigfun,NULL);
-
- if(ret)
- Py_DECREF(ret);
- else {
-#ifdef FLEXT_DEBUG
- PyErr_Print();
-#else
- PyErr_Clear();
-#endif
- }
- PyUnlock(state);
-}
-
-PyObject *pydsp::GetSig(int ix,bool in)
-{
- PyObject *r = buffers[in?ix:CntInSig()+ix];
- Py_XINCREF(r);
- return r;
-}
-
-#endif
+/* + +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. + +*/ + +#ifndef PY_NODSP + +#include "pyext.h" + +class pydsp + : public pyext +{ + FLEXT_HEADER(pydsp,pyext) +public: + pydsp(int argc,const t_atom *argv); + +protected: + virtual bool CbDsp(); + virtual void CbSignal(); + + virtual bool DoInit(); + virtual void DoExit(); + + virtual PyObject *GetSig(int ix,bool in); + + void NewBuffers(); + void FreeBuffers(); + + PyObject *dspfun,*sigfun; + PyObject **buffers; +}; + +FLEXT_LIB_DSP_V("pyext~ pyext.~ pyx~ pyx.~",pydsp) + +pydsp::pydsp(int argc,const t_atom *argv) + : pyext(argc,argv,true) + , dspfun(NULL),sigfun(NULL) +{} + +bool pydsp::DoInit() +{ + if(!pyext::DoInit()) return false; + + if(pyobj) + { + dspfun = PyObject_GetAttrString(pyobj,"_dsp"); // get ref + if(!dspfun) + PyErr_Clear(); + else if(!PyMethod_Check(dspfun)) { + Py_DECREF(dspfun); + dspfun = NULL; + } + } + return true; +} + +void pydsp::DoExit() +{ + if(dspfun) { Py_DECREF(dspfun); dspfun = NULL; } + if(sigfun) { Py_DECREF(sigfun); sigfun = NULL; } + + FreeBuffers(); +} + +PyObject *arrayfrombuffer(PyObject *buf,int c,int n); + +void pydsp::NewBuffers() +{ + int i,n = Blocksize(); + const int ins = CntInSig(),outs = CntOutSig(); + t_sample *const *insigs = InSig(); + t_sample *const *outsigs = OutSig(); + + // inlet/outlet count can't change so we don't have to deallocate + if(!buffers) { + int cnt = ins+outs; + buffers = new PyObject *[cnt]; + memset(buffers,0,cnt*sizeof(*buffers)); + } + + for(i = 0; i < ins; ++i) { + Py_XDECREF(buffers[i]); + PyObject *b = PyBuffer_FromReadWriteMemory(insigs[i],n*sizeof(t_sample)); + buffers[i] = arrayfrombuffer(b,1,n); + Py_DECREF(b); + } + for(i = 0; i < outs; ++i) { + Py_XDECREF(buffers[ins+i]); + if(i < ins && outsigs[i] == insigs[i]) { + // same vectors - share the objects! + buffers[ins+i] = buffers[i]; + Py_XINCREF(buffers[i]); + } + else { + PyObject *b = PyBuffer_FromReadWriteMemory(outsigs[i],n*sizeof(t_sample)); + buffers[ins+i] = arrayfrombuffer(b,1,n); + Py_DECREF(b); + } + } +} + +void pydsp::FreeBuffers() +{ + if(buffers) { + int cnt = CntInSig()+CntOutSig(); + for(int i = 0; i < cnt; ++i) Py_XDECREF(buffers[i]); + delete[] buffers; + buffers = NULL; + } +} + +bool pydsp::CbDsp() +{ + if(pyobj && (CntInSig() || CntOutSig())) + { + ThrState state = PyLockSys(); + + NewBuffers(); + + bool dodsp = true; + if(dspfun) { + PyObject *ret = PyObject_CallObject(dspfun,NULL); + if(ret) { + dodsp = PyObject_IsTrue(ret) != 0; + Py_DECREF(ret); + } + else { +#ifdef FLEXT_DEBUG + PyErr_Print(); +#else + PyErr_Clear(); +#endif + } + } + + // do that here instead of where dspfun is initialized, so that + // _signal can be assigned in _dsp + // optimizations may be done there to assign the right _signal version + Py_XDECREF(sigfun); + + if(dodsp) { + sigfun = PyObject_GetAttrString(pyobj,"_signal"); // get ref + if(!sigfun) + PyErr_Clear(); + else if(!PyMethod_Check(sigfun)) { + Py_DECREF(sigfun); + sigfun = NULL; + } + } + else + sigfun = NULL; + + PyUnlock(state); + return sigfun != NULL; + } + else + // switch on dsp only if there are signal inlets or outlets + return false; +} + +void pydsp::CbSignal() +{ + ThrState state = PyLockSys(); + PyObject *ret = PyObject_CallObject(sigfun,NULL); + + if(ret) + Py_DECREF(ret); + else { +#ifdef FLEXT_DEBUG + PyErr_Print(); +#else + PyErr_Clear(); +#endif + } + PyUnlock(state); +} + +PyObject *pydsp::GetSig(int ix,bool in) +{ + PyObject *r = buffers[in?ix:CntInSig()+ix]; + Py_XINCREF(r); + return r; +} + +#endif diff --git a/externals/grill/py/source/pyext.cpp b/externals/grill/py/source/pyext.cpp index 5c573bd2..31945277 100644 --- a/externals/grill/py/source/pyext.cpp +++ b/externals/grill/py/source/pyext.cpp @@ -117,8 +117,10 @@ pyext::pyext(int argc,const t_atom *argv,bool sig): methname(NULL), pyobj(NULL), inlets(-1),outlets(-1), - siginlets(0),sigoutlets(0), - pythr(NULL) + siginlets(0),sigoutlets(0) +#ifndef PY_USE_GIL + ,pythr(NULL) +#endif { #ifdef FLEXT_THREADS FLEXT_ADDTIMER(stoptmr,tick); @@ -141,7 +143,7 @@ pyext::pyext(int argc,const t_atom *argv,bool sig): // check if the object name is pyext. , pyx. or similar bool dotted = strrchr(thisName(),'.') != NULL; - PyThreadState *state = PyLockSys(); + ThrState state = PyLockSys(); // init script module if(argc) { @@ -194,7 +196,7 @@ pyext::pyext(int argc,const t_atom *argv,bool sig): bool pyext::Init() { - PyThreadState *state = PyLockSys(); + ThrState state = PyLockSys(); if(methname) { MakeInstance(); @@ -221,7 +223,7 @@ void pyext::Exit() { pybase::Exit(); // exit threads - PyThreadState *state = PyLockSys(); + ThrState state = PyLockSys(); DoExit(); Unregister(GetRegistry(REGNAME)); @@ -414,7 +416,7 @@ void pyext::Unload() void pyext::m_get(const t_symbol *s) { - PyThreadState *state = PyLockSys(); + ThrState state = PyLockSys(); PyObject *pvar = PyObject_GetAttrString(pyobj,const_cast<char *>(GetString(s))); /* fetch bound method */ if(pvar) { @@ -437,7 +439,7 @@ void pyext::m_get(const t_symbol *s) void pyext::m_set(int argc,const t_atom *argv) { - PyThreadState *state = PyLockSys(); + ThrState state = PyLockSys(); if(argc < 2 || !IsString(argv[0])) post("%s - Syntax: set varname arguments...",thisName()); @@ -542,7 +544,7 @@ bool pyext::work(int n,const t_symbol *s,int argc,const t_atom *argv) { bool ret = false; - PyThreadState *state = PyLock(); + ThrState state = PyLock(); // should be enough... char str[256]; diff --git a/externals/grill/py/source/pyext.h b/externals/grill/py/source/pyext.h index 4696c72c..da08aa53 100644 --- a/externals/grill/py/source/pyext.h +++ b/externals/grill/py/source/pyext.h @@ -114,7 +114,9 @@ private: virtual void callpy(PyObject *fun,PyObject *args); static bool stcallpy(PyObject *fun,PyObject *args); - PyThreadState *pythr; +#ifndef PY_USE_GIL + ThrState pythr; +#endif private: static bool boundmeth(flext_base *,t_symbol *sym,int argc,t_atom *argv,void *data); diff --git a/externals/grill/py/source/pymeth.cpp b/externals/grill/py/source/pymeth.cpp index 3bc90ee2..ff0d6b83 100644 --- a/externals/grill/py/source/pymeth.cpp +++ b/externals/grill/py/source/pymeth.cpp @@ -1,428 +1,428 @@ -/*
-
-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);
-
- 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 void DumpOut(const t_symbol *sym,int argc,const t_atom *argv);
-
- PyObject **objects;
-
-private:
-
- virtual void 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(pymsg)
- 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)
-#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,"py",pymsg);
- 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);
-#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);
-}
-
-void pymeth::callpy(PyObject *fun,PyObject *args)
-{
- PyObject *ret = PyObject_CallObject(fun,args);
- if(ret) {
- OutObject(this,0,ret); // exception might be raised here
- Py_DECREF(ret);
- }
-}
-
-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 = PyLockSys();
-
- 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]);
- }
-
- gencall(function,pargs); // references are stolen
- ret = true;
- }
- else
- PyErr_SetString(PyExc_RuntimeError,"No function set");
-
- Report();
- }
-
- PyUnlock(state);
-
- Respond(ret);
-
- return ret;
-}
-
-void pymeth::DumpOut(const t_symbol *sym,int argc,const t_atom *argv)
-{
- ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv);
-}
+/* + +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); + + 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 void DumpOut(const t_symbol *sym,int argc,const t_atom *argv); + + PyObject **objects; + +private: + + virtual void 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(pymsg) + 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) +#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,"py",pymsg); + 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); +#endif + + ThrState 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; + } + + ThrState 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) +{ + ThrState 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); +} + +void pymeth::callpy(PyObject *fun,PyObject *args) +{ + PyObject *ret = PyObject_CallObject(fun,args); + if(ret) { + OutObject(this,0,ret); // exception might be raised here + Py_DECREF(ret); + } +} + +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); + + ThrState state = PyLockSys(); + + 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]); + } + + gencall(function,pargs); // references are stolen + ret = true; + } + else + PyErr_SetString(PyExc_RuntimeError,"No function set"); + + Report(); + } + + PyUnlock(state); + + Respond(ret); + + return ret; +} + +void pymeth::DumpOut(const t_symbol *sym,int argc,const t_atom *argv) +{ + ToOutAnything(GetOutAttr(),sym?sym:thisTag(),argc,argv); +} diff --git a/externals/grill/py/source/pyprefix.h b/externals/grill/py/source/pyprefix.h index de74ca42..9be12e85 100644 --- a/externals/grill/py/source/pyprefix.h +++ b/externals/grill/py/source/pyprefix.h @@ -1,43 +1,43 @@ -/*
-
-py/pyext - python script object for PD and MaxMSP
-
-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.
-
-*/
-
-#ifndef __PYPREFIX_H
-#define __PYPREFIX_H
-
-#define FLEXT_ATTRIBUTES 1
-#include <flext.h>
-
-// hack: must include math.h before Python.h (at least on OSX)
-// otherwise some functions don't get defined
-#include <math.h>
-
-#if FLEXT_OS == FLEXT_OS_MAC
-#include <Python/Python.h>
-#else
-#include <Python.h>
-#endif
-
-#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 501)
-#error You need at least flext version 0.5.1
-#endif
-
-#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
-
-#include <flcontainers.h>
-#include <string>
-
-
-#endif
+/* + +py/pyext - python script object for PD and MaxMSP + +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. + +*/ + +#ifndef __PYPREFIX_H +#define __PYPREFIX_H + +#define FLEXT_ATTRIBUTES 1 +#include <flext.h> + +// hack: must include math.h before Python.h (at least on OSX) +// otherwise some functions don't get defined +#include <math.h> + +#if FLEXT_OS == FLEXT_OS_MAC +#include <Python/Python.h> +#else +#include <Python.h> +#endif + +#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 501) +#error You need at least flext version 0.5.1 +#endif + +#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 + +#include <flcontainers.h> +#include <string> + + +#endif diff --git a/externals/grill/py/source/pysymbol.cpp b/externals/grill/py/source/pysymbol.cpp index 2f023469..f907cc45 100644 --- a/externals/grill/py/source/pysymbol.cpp +++ b/externals/grill/py/source/pysymbol.cpp @@ -1,254 +1,254 @@ -/*
-
-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 "pyprefix.h"
-#include "pysymbol.h"
-
-inline pySymbol *symbol_newsym(const t_symbol *sym)
-{
- pySymbol *self = (pySymbol *)pySymbol_Type.tp_alloc(&pySymbol_Type, 0);
- if(self) self->sym = sym;
- return self;
-}
-
-static PyObject *symbol_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- return (PyObject *)symbol_newsym(flext::sym__);
-}
-
-static int symbol_init(PyObject *self, PyObject *args, PyObject *kwds)
-{
- FLEXT_ASSERT(pySymbol_Check(self));
-
- PyObject *arg = PySequence_GetItem(args,0); // new reference
- if(!arg) return -1;
-
- int ret = 0;
-
- if(pySymbol_Check(arg))
- ((pySymbol *)self)->sym = pySymbol_AS_SYMBOL(arg);
- else if(PyString_Check(arg))
- ((pySymbol *)self)->sym = flext::MakeSymbol(PyString_AS_STRING(arg));
- else {
- PyErr_SetString(PyExc_TypeError,"string or symbol argument expected");
- ret = -1;
- }
- Py_DECREF(arg);
-
- return ret;
-}
-
-static PyObject *symbol_str(PyObject *self)
-{
- FLEXT_ASSERT(pySymbol_Check(self));
- return (PyObject *)PyString_FromString(pySymbol_AS_STRING(self));
-}
-
-static PyObject *symbol_repr(PyObject *self)
-{
- FLEXT_ASSERT(pySymbol_Check(self));
- return (PyObject *)PyString_FromFormat("<Symbol %s>",pySymbol_AS_STRING(self));
-}
-
-static PyObject *symbol_richcompare(PyObject *a,PyObject *b,int cmp)
-{
- if(pySymbol_Check(a) && pySymbol_Check(b)) {
- const t_symbol *asym = pySymbol_AS_SYMBOL(a);
- const t_symbol *bsym = pySymbol_AS_SYMBOL(b);
- bool ret;
- switch(cmp) {
- case Py_LT: ret = asym < bsym; break;
- case Py_LE: ret = asym <= bsym; break;
- case Py_EQ: ret = asym == bsym; break;
- case Py_NE: ret = asym != bsym; break;
- case Py_GT: ret = asym > bsym; break;
- case Py_GE: ret = asym >= bsym; break;
- }
- return PyBool_FromLong(ret);
- }
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
-}
-
-static long symbol_hash(PyObject *self)
-{
- FLEXT_ASSERT(pySymbol_Check(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*/
- "Symbol", /*tp_name*/
- sizeof(pySymbol), /*tp_basicsize*/
- 0, /*tp_itemsize*/
- 0, /*tp_dealloc*/
- 0, /*tp_print*/
- 0, /*tp_getattr*/
- 0, /*tp_setattr*/
- 0, /*tp_compare*/
- symbol_repr, /*tp_repr*/
- 0, /*tp_as_number*/
- &symbol_as_seq, /*tp_as_sequence*/
- 0, /*tp_as_mapping*/
- symbol_hash, /*tp_hash */
- 0, /*tp_call*/
- symbol_str, /*tp_str*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- 0, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/, /*tp_flags*/
- "Symbol objects", /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- symbol_richcompare, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- symbol_iter, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- symbol_init, /* tp_init */
- 0, /* tp_alloc */
- symbol_new, /* tp_new */
-};
-
-pySymbol *pySymbol__;
-pySymbol *pySymbol_bang;
-pySymbol *pySymbol_list;
-pySymbol *pySymbol_symbol;
-pySymbol *pySymbol_float;
-pySymbol *pySymbol_int;
-
-
-void initsymbol()
-{
- if(PyType_Ready(&pySymbol_Type) < 0)
- return;
-
- Py_INCREF(&pySymbol_Type);
-
- // initialize predefined objects
- pySymbol__ = symbol_newsym(flext::sym__);
- pySymbol_bang = symbol_newsym(flext::sym_bang);
- pySymbol_list = symbol_newsym(flext::sym_list);
- pySymbol_symbol = symbol_newsym(flext::sym_symbol);
- pySymbol_float = symbol_newsym(flext::sym_float);
- pySymbol_int = symbol_newsym(flext::sym_int);
-}
-
-
-PyObject *pySymbol_FromSymbol(const t_symbol *sym)
-{
- pySymbol *op;
- if(sym == flext::sym__)
- Py_INCREF(op = pySymbol__);
- else if(sym == flext::sym_bang)
- Py_INCREF(op = pySymbol_bang);
- else if(sym == flext::sym_list)
- Py_INCREF(op = pySymbol_list);
- else if(sym == flext::sym_symbol)
- Py_INCREF(op = pySymbol_symbol);
- else if(sym == flext::sym_float)
- Py_INCREF(op = pySymbol_float);
- else if(sym == flext::sym_int)
- Py_INCREF(op = pySymbol_int);
- else
- op = symbol_newsym(sym);
- return (PyObject *)op;
-}
+/* + +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 "pyprefix.h" +#include "pysymbol.h" + +inline pySymbol *symbol_newsym(const t_symbol *sym) +{ + pySymbol *self = (pySymbol *)pySymbol_Type.tp_alloc(&pySymbol_Type, 0); + if(self) self->sym = sym; + return self; +} + +static PyObject *symbol_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return (PyObject *)symbol_newsym(flext::sym__); +} + +static int symbol_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + FLEXT_ASSERT(pySymbol_Check(self)); + + PyObject *arg = PySequence_GetItem(args,0); // new reference + if(!arg) return -1; + + int ret = 0; + + if(pySymbol_Check(arg)) + ((pySymbol *)self)->sym = pySymbol_AS_SYMBOL(arg); + else if(PyString_Check(arg)) + ((pySymbol *)self)->sym = flext::MakeSymbol(PyString_AS_STRING(arg)); + else { + PyErr_SetString(PyExc_TypeError,"string or symbol argument expected"); + ret = -1; + } + Py_DECREF(arg); + + return ret; +} + +static PyObject *symbol_str(PyObject *self) +{ + FLEXT_ASSERT(pySymbol_Check(self)); + return (PyObject *)PyString_FromString(pySymbol_AS_STRING(self)); +} + +static PyObject *symbol_repr(PyObject *self) +{ + FLEXT_ASSERT(pySymbol_Check(self)); + return (PyObject *)PyString_FromFormat("<Symbol %s>",pySymbol_AS_STRING(self)); +} + +static PyObject *symbol_richcompare(PyObject *a,PyObject *b,int cmp) +{ + if(pySymbol_Check(a) && pySymbol_Check(b)) { + const t_symbol *asym = pySymbol_AS_SYMBOL(a); + const t_symbol *bsym = pySymbol_AS_SYMBOL(b); + bool ret; + switch(cmp) { + case Py_LT: ret = asym < bsym; break; + case Py_LE: ret = asym <= bsym; break; + case Py_EQ: ret = asym == bsym; break; + case Py_NE: ret = asym != bsym; break; + case Py_GT: ret = asym > bsym; break; + case Py_GE: ret = asym >= bsym; break; + } + return PyBool_FromLong(ret); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static long symbol_hash(PyObject *self) +{ + FLEXT_ASSERT(pySymbol_Check(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*/ + "Symbol", /*tp_name*/ + sizeof(pySymbol), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + symbol_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + &symbol_as_seq, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + symbol_hash, /*tp_hash */ + 0, /*tp_call*/ + symbol_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT /*| Py_TPFLAGS_BASETYPE*/, /*tp_flags*/ + "Symbol objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + symbol_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + symbol_iter, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + symbol_init, /* tp_init */ + 0, /* tp_alloc */ + symbol_new, /* tp_new */ +}; + +pySymbol *pySymbol__; +pySymbol *pySymbol_bang; +pySymbol *pySymbol_list; +pySymbol *pySymbol_symbol; +pySymbol *pySymbol_float; +pySymbol *pySymbol_int; + + +void initsymbol() +{ + if(PyType_Ready(&pySymbol_Type) < 0) + return; + + Py_INCREF(&pySymbol_Type); + + // initialize predefined objects + pySymbol__ = symbol_newsym(flext::sym__); + pySymbol_bang = symbol_newsym(flext::sym_bang); + pySymbol_list = symbol_newsym(flext::sym_list); + pySymbol_symbol = symbol_newsym(flext::sym_symbol); + pySymbol_float = symbol_newsym(flext::sym_float); + pySymbol_int = symbol_newsym(flext::sym_int); +} + + +PyObject *pySymbol_FromSymbol(const t_symbol *sym) +{ + pySymbol *op; + if(sym == flext::sym__) + Py_INCREF(op = pySymbol__); + else if(sym == flext::sym_bang) + Py_INCREF(op = pySymbol_bang); + else if(sym == flext::sym_list) + Py_INCREF(op = pySymbol_list); + else if(sym == flext::sym_symbol) + Py_INCREF(op = pySymbol_symbol); + else if(sym == flext::sym_float) + Py_INCREF(op = pySymbol_float); + else if(sym == flext::sym_int) + Py_INCREF(op = pySymbol_int); + else + op = symbol_newsym(sym); + return (PyObject *)op; +} diff --git a/externals/grill/py/source/pysymbol.h b/externals/grill/py/source/pysymbol.h index 42f6765c..3de4cb00 100644 --- a/externals/grill/py/source/pysymbol.h +++ b/externals/grill/py/source/pysymbol.h @@ -1,55 +1,55 @@ -/*
-
-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.
-
-*/
-
-#ifndef __PYSYMBOL_H
-#define __PYSYMBOL_H
-
-#include <flext.h>
-
-#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500)
-#error You need at least flext version 0.5.0
-#endif
-
-#if FLEXT_OS == FLEXT_OS_MAC
-#include <Python/Python.h>
-#else
-#include <Python.h>
-#endif
-
-
-#ifdef _MSC_VER
- #ifdef PY_EXPORTS
- #define PY_EXPORT __declspec(dllexport)
- #else
- #define PY_EXPORT __declspec(dllimport)
- #endif
-#else
- #define PY_EXPORT
-#endif
-
-typedef struct {
- PyObject_HEAD
- /* Type-specific fields go here. */
- const t_symbol *sym;
-} pySymbol;
-
-PY_EXPORT extern PyTypeObject pySymbol_Type;
-
-PY_EXPORT extern pySymbol *pySymbol__;
-PY_EXPORT extern pySymbol *pySymbol_bang;
-PY_EXPORT extern pySymbol *pySymbol_list;
-PY_EXPORT extern pySymbol *pySymbol_symbol;
-PY_EXPORT extern pySymbol *pySymbol_float;
-PY_EXPORT extern pySymbol *pySymbol_int;
-
-
+/* + +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. + +*/ + +#ifndef __PYSYMBOL_H +#define __PYSYMBOL_H + +#include <flext.h> + +#if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 500) +#error You need at least flext version 0.5.0 +#endif + +#if FLEXT_OS == FLEXT_OS_MAC +#include <Python/Python.h> +#else +#include <Python.h> +#endif + + +#ifdef _MSC_VER + #ifdef PY_EXPORTS + #define PY_EXPORT __declspec(dllexport) + #else + #define PY_EXPORT __declspec(dllimport) + #endif +#else + #define PY_EXPORT +#endif + +typedef struct { + PyObject_HEAD + /* Type-specific fields go here. */ + const t_symbol *sym; +} pySymbol; + +PY_EXPORT extern PyTypeObject pySymbol_Type; + +PY_EXPORT extern pySymbol *pySymbol__; +PY_EXPORT extern pySymbol *pySymbol_bang; +PY_EXPORT extern pySymbol *pySymbol_list; +PY_EXPORT extern pySymbol *pySymbol_symbol; +PY_EXPORT extern pySymbol *pySymbol_float; +PY_EXPORT extern pySymbol *pySymbol_int; + + #define pySymbol_Check(op) PyObject_TypeCheck(op, &pySymbol_Type) #define pySymbol_CheckExact(op) ((op)->ob_type == &pySymbol_Type) @@ -66,27 +66,27 @@ inline PyObject *pySymbol_FromString(PyObject *str) return pySymbol_FromString(PyString_AsString(str)); } -inline const t_symbol *pySymbol_AS_SYMBOL(PyObject *op)
-{
- return ((pySymbol *)op)->sym;
-}
-
-inline const t_symbol *pySymbol_AsSymbol(PyObject *op)
-{
- return pySymbol_Check(op)?pySymbol_AS_SYMBOL(op):NULL;
-}
-
-inline const char *pySymbol_AS_STRING(PyObject *op)
-{
- return flext::GetString(pySymbol_AS_SYMBOL(op));
-}
-
-inline const t_symbol *pyObject_AsSymbol(PyObject *op)
-{
- if(PyString_Check(op))
- return flext::MakeSymbol(PyString_AS_STRING(op));
- else
- return pySymbol_AsSymbol(op);
-}
-
-#endif
+inline const t_symbol *pySymbol_AS_SYMBOL(PyObject *op) +{ + return ((pySymbol *)op)->sym; +} + +inline const t_symbol *pySymbol_AsSymbol(PyObject *op) +{ + return pySymbol_Check(op)?pySymbol_AS_SYMBOL(op):NULL; +} + +inline const char *pySymbol_AS_STRING(PyObject *op) +{ + return flext::GetString(pySymbol_AS_SYMBOL(op)); +} + +inline const t_symbol *pyObject_AsSymbol(PyObject *op) +{ + if(PyString_Check(op)) + return flext::MakeSymbol(PyString_AS_STRING(op)); + else + return pySymbol_AsSymbol(op); +} + +#endif |