[Zope-Checkins] CVS: Zope2 - CHANGES.txt:1.2 PythonScript.py:1.27 standard.py:1.5 version.txt:1.3 Guarded.py:NONE
shane@digicool.com
shane@digicool.com
Fri, 27 Apr 2001 16:28:17 -0400 (EDT)
Update of /cvs-repository/Zope2/lib/python/Products/PythonScripts
In directory korak:/tmp/cvs-serv17686/lib/python/Products/PythonScripts
Modified Files:
CHANGES.txt PythonScript.py standard.py version.txt
Removed Files:
Guarded.py
Log Message:
Merged RestrictedPythonBranch!
--- Updated File CHANGES.txt in package Zope2 --
--- CHANGES.txt 2000/11/30 22:18:03 1.1
+++ CHANGES.txt 2001/04/27 20:27:43 1.2
@@ -1,3 +1,9 @@
+2001-04-26 Evan Simpson <evan@digicool.com>
+
+ * Version 2.0.0
+ * Totally replaced zbytecodhacks engine with Zope's new
+ RestrictedPython package, which it shares with DTML.
+
1999-12-13 Evan Simpson <evan@4-am.com>
* Version 0.1.7
--- Updated File PythonScript.py in package Zope2 --
--- PythonScript.py 2001/04/11 15:35:44 1.26
+++ PythonScript.py 2001/04/27 20:27:43 1.27
@@ -91,12 +91,11 @@
__version__='$Revision$'[11:-2]
-import sys, os, traceback, re
+import sys, os, traceback, re, marshal
from Globals import DTMLFile, MessageDialog, package_home
-import AccessControl, OFS, Guarded
+import AccessControl, OFS, RestrictedPython
from OFS.SimpleItem import SimpleItem
from DateTime.DateTime import DateTime
-from string import join, strip, rstrip, split, replace, lower
from urllib import quote
from webdav.Lockable import ResourceLockedError
from webdav.WriteLockInterface import WriteLockInterface
@@ -104,12 +103,17 @@
from AccessControl import getSecurityManager
from OFS.History import Historical, html_diff
from OFS.Cache import Cacheable
-from zLOG import LOG, ERROR, INFO
+from AccessControl import full_read_guard, full_write_guard, safe_builtins
+from zLOG import LOG, ERROR, INFO, PROBLEM
+# Track the Python bytecode version
import imp
Python_magic = imp.get_magic()
del imp
+# This should only be incremented to force recompilation.
+Script_magic = 1
+
manage_addPythonScriptForm = DTMLFile('www/pyScriptAdd', globals())
_default_file = os.path.join(package_home(globals()),
'www', 'default.py')
@@ -145,6 +149,8 @@
_proxy_roles = ()
_params = _body = ''
+ errors = warnings = ()
+ _v_change = 0
manage_options = (
{'label':'Edit',
@@ -187,9 +193,6 @@
self.ZPythonScript_setTitle(title)
self.ZPythonScript_edit(params, body)
message = "Saved changes."
- if getattr(self, '_v_warnings', None):
- message = ("<strong>Warning:</strong> <i>%s</i>"
- % join(self._v_warnings, '<br>'))
return self.ZPythonScriptHTML_editForm(self, REQUEST,
manage_tabs_message=message)
@@ -205,7 +208,7 @@
raise ResourceLockedError, "The script is locked via WebDAV."
if type(body) is not type(''):
body = body.read()
- if self._params <> params or self._body <> body:
+ if self._params <> params or self._body <> body or self._v_change:
self._params = str(params)
self.write(body)
@@ -238,10 +241,10 @@
def ZScriptHTML_tryParams(self):
"""Parameters to test the script with."""
param_names = []
- for name in split(self._params, ','):
- name = strip(name)
+ for name in self._params.split(','):
+ name = name.strip()
if name and name[0] != '*':
- param_names.append(split(name, '=', 1)[0])
+ param_names.append(name.split('=', 1)[0])
return param_names
def manage_historyCompare(self, rev1, rev2, REQUEST,
@@ -250,58 +253,70 @@
self, rev1, rev2, REQUEST,
historyComparisonResults=html_diff(rev1.read(), rev2.read()) )
- def _checkCBlock(self, MakeBlock):
- params = self._params
- body = self._body or ' pass'
- # If the body isn't indented, indent it one space.
- nbc = re.search('\S', body).start()
- if nbc and body[nbc - 1] in ' \t':
- defblk = 'def f(%s):\n%s\n' % (params, body)
+ def __setstate__(self, state):
+ Script.__setstate__(self, state)
+ if (getattr(self, 'Python_magic', None) != Python_magic or
+ getattr(self, 'Script_magic', None) != Script_magic):
+ LOG(self.meta_type, PROBLEM,
+ 'Object "%s" needs to be recompiled.' % self.id)
+ # Changes here won't get saved, unless this Script is edited.
+ self._compile()
+ self._v_change = 1
+ elif self._code is None:
+ self._v_f = None
else:
- # Waaa: triple-quoted strings will get indented too.
- defblk = 'def f(%s):\n %s\n' % (params, replace(body, '\n', '\n '))
+ self._newfun(marshal.loads(self._code))
- blk = MakeBlock(defblk, self.id, self.meta_type)
- self._v_errors, self._v_warnings = blk.errors, blk.warnings
- if blk.errors:
- if hasattr(self, '_v_f'): del self._v_f
+ def _compiler(self, *args):
+ return RestrictedPython.compile_restricted_function(*args)
+ def _compile(self):
+ r = self._compiler(self._params, self._body or 'pass',
+ self.id, self.meta_type)
+ code = r[0]
+ errors = r[1]
+ self.warnings = tuple(r[2])
+ if errors:
+ self._code = None
+ self._v_f = None
self._setFuncSignature((), (), 0)
- else:
- self._t = blk.t
+ # Fix up syntax errors.
+ filestring = ' File "<string>",'
+ for i in range(len(errors)):
+ line = errors[i]
+ if line.startswith(filestring):
+ errors[i] = line.replace(filestring, ' Script', 1)
+ self.errors = errors
+ return
- def _newfun(self, allowSideEffect, g, **kws):
- from Guarded import UntupleFunction
- self._v_f = f = apply(UntupleFunction, (self._t, g), kws)
- if allowSideEffect:
- fc = f.func_code
- self._setFuncSignature(f.func_defaults, fc.co_varnames,
- fc.co_argcount)
- self.Python_magic = Python_magic
+ self._code = marshal.dumps(code)
+ self.errors = ()
+ f = self._newfun(code)
+ fc = f.func_code
+ self._setFuncSignature(f.func_defaults, fc.co_varnames,
+ fc.co_argcount)
+ self.Python_magic = Python_magic
+ self.Script_magic = Script_magic
+ self._v_change = 0
+
+ def _newfun(self, code):
+ g = {'__debug__': __debug__,
+ '__builtins__': safe_builtins,
+ '_read_': full_read_guard,
+ '_write_': full_write_guard,
+ '_print_': RestrictedPython.PrintCollector
+ }
+ l = {}
+ exec code in g, l
+ self._v_f = f = l.values()[0]
return f
- def _makeFunction(self, allowSideEffect=0):
- from Guarded import GuardedBlock, theGuard, safebin
- from Guarded import WriteGuard, ReadGuard
- # Was the cached bytecode compiled with a compatible Python?
- if getattr(self, 'Python_magic', None) != Python_magic:
- allowSideEffect = 1
- if allowSideEffect:
- self._checkCBlock(GuardedBlock)
- self.ZCacheable_invalidate()
- if getattr(self, '_v_errors', None):
- raise "Python Script Error", ('<pre>%s</pre>' %
- join(self._v_errors, '\n') )
- return self._newfun(allowSideEffect, {'$guard': theGuard,
- '$write_guard': WriteGuard,
- '$read_guard': ReadGuard,
- '__debug__': __debug__},
- __builtins__=safebin)
+ def _makeFunction(self):
+ self.ZCacheable_invalidate()
+ self._compile()
def _editedBindings(self):
- f = getattr(self, '_v_f', None)
- if f is None:
- return
- self._makeFunction(1)
+ if getattr(self, '_v_f', None) is not None:
+ self._makeFunction()
def _exec(self, bound_names, args, kw):
"""Call a Python Script
@@ -327,13 +342,11 @@
# Got a cached value.
return result
- # Prepare the function.
- f = getattr(self, '_v_f', None)
- if f is None:
- f = self._makeFunction()
-
__traceback_info__ = bound_names, args, kw, self.func_defaults
+ f = self._v_f
+ if f is None:
+ raise RuntimeError, '%s %s has errors.' % (self.meta_type, self.id)
if bound_names is not None:
# Updating func_globals directly *should* be thread-safe.
f.func_globals.update(bound_names)
@@ -414,7 +427,7 @@
# There were no non-empty body lines
body = ''
break
- line = strip(m.group(0))
+ line = m.group(0).strip()
if line[:2] != '##':
# We have found the first line of the body
body = text[m.start(0):]
@@ -425,9 +438,9 @@
if len(line) == 2 or line[2] == ' ' or '=' not in line:
# Null header line
continue
- k, v = split(line[2:], '=', 1)
- k = lower(strip(k))
- v = strip(v)
+ k, v = line[2:].split('=', 1)
+ k = k.strip().lower()
+ v = v.strip()
if not mdata.has_key(k):
SyntaxError, 'Unrecognized header line "%s"' % line
if v == mdata[k]:
@@ -443,14 +456,14 @@
bindmap[_nice_bind_names[k[5:]]] = v
bup = 1
- body = rstrip(body)
+ body = body.rstrip()
if body != self._body:
self._body = body
if bup:
self._setupBindings(bindmap)
if self._p_changed:
- self._makeFunction(1)
+ self._makeFunction()
except:
LOG(self.meta_type, ERROR, 'write failed', error=sys.exc_info())
raise
@@ -486,8 +499,18 @@
mm.sort()
for kv in mm:
hlines.append('%s=%s' % kv)
+ if self.errors:
+ hlines.append('')
+ hlines.append(' Errors:')
+ for line in self.errors:
+ hlines.append(' ' + line)
+ if self.warnings:
+ hlines.append('')
+ hlines.append(' Warnings:')
+ for line in self.warnings:
+ hlines.append(' ' + line)
hlines.append('')
- return join(hlines, '\n' + prefix) + '\n' + self._body
+ return ('\n' + prefix).join(hlines) + '\n' + self._body
def params(self): return self._params
def body(self): return self._body
--- Updated File standard.py in package Zope2 --
--- standard.py 2001/01/04 00:36:44 1.4
+++ standard.py 2001/04/27 20:27:43 1.5
@@ -105,6 +105,7 @@
html_quote, url_quote, url_quote_plus, newline_to_br, thousands_commas
from Globals import HTML
+from AccessControl import full_read_guard
security.declarePublic('DTML')
class DTML(HTML):
@@ -121,8 +122,8 @@
finally: security.removeContext(self)
- def validate(self, inst, parent, name, value, md):
- return getSecurityManager().validate(inst, parent, name, value)
+ def read_guard(self, ob):
+ return full_read_guard(ob)
security.apply(globals())
--- Updated File version.txt in package Zope2 --
--- version.txt 2001/02/27 17:35:17 1.2
+++ version.txt 2001/04/27 20:27:43 1.3
@@ -1 +1 @@
-PythonScripts-1-0-1
+PythonScripts-2-0-0
--- Removed file Guarded.py from package Zope2 --