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:
		
							parent
							
								
									714cc67541
								
							
						
					
					
						commit
						525050654a
					
				
					 5 changed files with 100 additions and 23 deletions
				
			
		|  | @ -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" | ||||||
|  |  | ||||||
|  | @ -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", | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  | @ -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() | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 helmutm
						helmutm