Improved handling of R plots

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2042 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-09-16 10:16:15 +00:00
parent 714cc67541
commit 525050654a
5 changed files with 100 additions and 23 deletions

View file

@ -20,7 +20,7 @@
/> />
<require <require
permission="zope.ManageContent" permission="zope.ManageContent"
set_attributes="source contentType" set_attributes="parameters source contentType"
/> />
<implements <implements
interface="zope.annotation.interfaces.IAttributeAnnotatable" interface="zope.annotation.interfaces.IAttributeAnnotatable"

View file

@ -38,15 +38,21 @@ class IPythonScript(Interface):
automatically. automatically.
""" """
parameters = schema.TextLine(
title=_(u"Parameters"),
description=_(u"Space-separated list of parameter names."),
required=False,
default=u''
)
source = schema.SourceText( source = schema.SourceText(
title=_(u"Source"), title=_(u"Source"),
description=_(u"The source of the Python page."), description=_(u"The source of the Python page."),
required=True, required=True,
) )
contentType = schema.TextLine( contentType = schema.TextLine(
title=_(u"Content Type"), title=_(u"Content Type"),
description=_(u"The content type the script outputs."), description=_(u"The content type of the script's output (return value "
"when rendered in the browser)."),
required=True, required=True,
default=u"text/html", default=u"text/html",
) )

View file

@ -17,20 +17,46 @@
# #
""" """
View class(es) for images (plots). Management of filesystem images (plots) and corresponding views.
$Id$ $Id$
""" """
import os import os
import time
from zope.interface import Interface, implements from zope.interface import Interface, implements
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from cybertools.util import randomname, jeep
class CachedImage(object):
""" Keep information about temporary image files.
"""
def __init__(self, path, name=None):
self.path = path
if name is None:
self.name = randomname.generateName(lambda x: x not in cachedImages)
else:
self.name = name
self.timeStamp = int(time.time())
cachedImages = jeep.Jeep()
def registerImage(filename, name=None):
image = CachedImage(filename, name)
cachedImages.append(image)
while len(cachedImages) > 10: # clean up old cache entries
old = cachedImages.pop(0).path
if os.path.exists(old):
os.unlink(old)
return image.name
class PlotView(object): class PlotView(object):
""" Abstract basic view class for Flash movies . """ Access to temporary filesystem images.
The assessment attribute has to be set by the subclass.
""" """
def __init__(self, context, request): def __init__(self, context, request):
@ -44,10 +70,10 @@ class PlotView(object):
def __call__(self): def __call__(self):
if self.traverse_subpath: if self.traverse_subpath:
path = str('/' + os.path.join(*self.traverse_subpath)) key = self.traverse_subpath[0]
else: else:
path = self.request.form.get('image') key = self.request.form.get('image', 'not_found')
# TODO: keep path in temporary dictionary with hashed keys. path = cachedImages[key].path
self.setHeaders(path) self.setHeaders(path)
f = open(path, 'rb') f = open(path, 'rb')
data = f.read() data = f.read()

View file

@ -26,6 +26,9 @@ import os
import rpy import rpy
from rpy import r from rpy import r
from zope.proxy import removeAllProxies from zope.proxy import removeAllProxies
from zope.traversing.browser import absoluteURL
from cybertools.pyscript.plot import registerImage
class RWrapper(object): class RWrapper(object):
@ -49,8 +52,36 @@ with_mode = RWrapper(rpy.with_mode)
#as_py = RWrapper(rpy.as_py) #as_py = RWrapper(rpy.as_py)
def graphics(*args, **kw): def gdd(**kw):
filename = os.tempnam() r.library('GDD')
rc = r.GDD(filename, *args, **kw) filename = os.tempnam(None, 'rplot')
return filename + '.jpg', rc robj = r.GDD(filename, type='jpg', **kw)
return filename + '.jpg', robj
def graphics(**kw):
context = kw.pop('context', None)
request = kw.pop('request', None)
fn, robj = gdd(**kw)
key = registerImage(fn)
return '%s/@@plot?image=%s' % (absoluteURL(context, request), key)
class RStat(object):
def __init__(self, context, request):
self.context = context
self.request = request
def gdd(self, **kw):
r.library('GDD')
filename = os.tempnam(None, 'rplot')
robj = r.GDD(filename, type='jpg', **kw)
return filename + '.jpg', robj
def graphics(self, **kw):
request = self.request
context = self.context
fn, robj = gdd(**kw)
key = registerImage(fn)
return '%s/@@plot?image=%s' % (absoluteURL(context, request), key)

View file

@ -89,11 +89,14 @@ class PythonScript(Contained, Persistent):
_v_compiled = None _v_compiled = None
def __init__(self, source=u'', contentType=u'text/plain'): parameters = u''
def __init__(self, source=u'', parameters=u'', contentType=u'text/plain'):
"""Initialize the object.""" """Initialize the object."""
super(PythonScript, self).__init__() super(PythonScript, self).__init__()
self.source = source self.source = source
self.contentType = contentType self.contentType = contentType
self.parameters = parameters or u''
def __filename(self): def __filename(self):
if self.__parent__ is None: if self.__parent__ is None:
@ -110,7 +113,8 @@ class PythonScript(Contained, Persistent):
self.__source = source self.__source = source
self.__prepared_source = self.prepareSource(source) self.__prepared_source = self.prepareSource(source)
# Compile objects cannot be pickled # Compile objects cannot be pickled
self._v_compiled = Function(self.__prepared_source, self.__filename()) self._v_compiled = Function(self.__prepared_source, self.parameters,
self.__filename())
_tripleQuotedString = re.compile( _tripleQuotedString = re.compile(
r"^([ \t]*)[uU]?([rR]?)(('''|\"\"\")(.*)\4)", re.MULTILINE | re.DOTALL) r"^([ \t]*)[uU]?([rR]?)(('''|\"\"\")(.*)\4)", re.MULTILINE | re.DOTALL)
@ -136,11 +140,11 @@ class PythonScript(Contained, Persistent):
source = property(getSource, setSource) source = property(getSource, setSource)
def __call__(self, request, **kw): def __call__(self, request, *args, **kw):
output = StringIO() output = StringIO()
if self._v_compiled is None: if self._v_compiled is None:
self._v_compiled = Function(self.__prepared_source, self._v_compiled = Function(self.__prepared_source, self.parameters,
self.__filename()) self.__filename(),)
parent = getParent(self) parent = getParent(self)
kw['request'] = request kw['request'] = request
kw['script'] = self kw['script'] = self
@ -149,7 +153,7 @@ class PythonScript(Contained, Persistent):
kw['script_result'] = None kw['script_result'] = None
if IScriptContainer.providedBy(parent): if IScriptContainer.providedBy(parent):
parent.updateGlobals(kw) parent.updateGlobals(kw)
self._v_compiled(kw) self._v_compiled(args, kw)
result = kw['script_result'] result = kw['script_result']
if result == output: if result == output:
result = result.getvalue().decode('unicode-escape') result = result.getvalue().decode('unicode-escape')
@ -160,8 +164,13 @@ class Function(object):
"""A compiled function. """A compiled function.
""" """
def __init__(self, source, filename='<string>'): parameters = ''
def __init__(self, source, parameters='', filename='<string>'):
lines = [] lines = []
if parameters:
self.parameters = str(parameters).split()
#print '*** Function.parameters:', repr(self.parameters)
lines.insert(0, 'def dummy(): \n pass') lines.insert(0, 'def dummy(): \n pass')
for line in source.splitlines(): for line in source.splitlines():
lines.append(' ' + line) lines.append(' ' + line)
@ -170,8 +179,10 @@ class Function(object):
#print '*** source:', source #print '*** source:', source
self.code = compile(source, filename, 'exec') self.code = compile(source, filename, 'exec')
def __call__(self, globals): def __call__(self, args, globals):
globals['__builtins__'] = SafeBuiltins globals['__builtins__'] = SafeBuiltins
for idx, p in enumerate(self.parameters):
globals[p] = args[idx]
exec self.code in globals, None exec self.code in globals, None
@ -192,7 +203,10 @@ class ScriptContainer(BTreeContainer):
def updateGlobals(self, globs): def updateGlobals(self, globs):
if HAS_R: if HAS_R:
from cybertools.pyscript import rstat from cybertools.pyscript import rstat
globs['rstat'] = rstat #globs['rstat'] = rstat
context = globs['context']
request = globs['request']
globs['rstat'] = rstat.RStat(context, request)
globs['r'] = r globs['r'] = r
globs['rpy'] = rpy globs['rpy'] = rpy