[zopeorg-checkins] CVS: Products/PythonMethod - CHANGES.txt:1.1 COPYRIGHT.txt:1.1 Guarded.py:1.1 PythonMethod.py:1.1 README.txt:1.1 __init__.py:1.1 version.txt:1.1
Sidnei da Silva
sidnei at x3ng.com.br
Fri May 30 11:17:47 EDT 2003
Update of /cvs-zopeorg/Products/PythonMethod
In directory cvs.zope.org:/tmp/cvs-serv19195/PythonMethod
Added Files:
CHANGES.txt COPYRIGHT.txt Guarded.py PythonMethod.py
README.txt __init__.py version.txt
Log Message:
Adding products needed for migration of NZO
=== Added File Products/PythonMethod/CHANGES.txt ===
1999-12-13 Evan Simpson <evan at 4-am.com>
* Version 0.1.7
* Nested functions and lambdas are now supported, with full safety.
* You can access all of the dtml-var format functions through a builtin
dictionary called special_formats (eg: special_formats['html-quote']).
* Handing off to Digital Creations for inclusion in CVS.
* Packaged with packProduct script, which excludes parent directories
and .pyc files. Makes for a smaller package, and doesn't step on
ownership/permissions of lib/python/Products path elements.
1999-12-01 Evan Simpson <evan at 4-am.com>
* Added COPYRIGHT.txt, making Wide Open Source licence (BSD-style)
explicit. (Mike Goldman provided the text, I provided the silly name).
* Jeff Rush donated a PrincipiaSearchSource method, so that
PythonMethod objects can be zcataloged to the same degree
as DTML Methods.
* Also from Jeff Rush, a document_src method, so that the source of
PythonMethods can be viewed via a "View Source" link if desired.
* If a PM has a 'traverse_subpath' parameter, you can now directly
traverse it. The elements of the subpath will then be put into a list
in 'traverse_subpath'. (thanks to Anthony Baxter)
1999-11-11 Evan Simpson <evan at 4-am.com>
* Version 0.1.6
* Fix to builtins messed up DTML Methods, so I re-fixed it.
1999-11-05 Evan Simpson <evan at 4-am.com>
* Version 0.1.5
* Killed *%#&$@ weird bug in which having 'add' documents in 'www'
subdirectory prevented rename, paste, or import of existing
PythonMethods! See use of '_www'.
* Range, test, and several other Zope 'builtins' had an unbound 'self'
argument unless called on _, but that's fixed.
* Safe multiplication was utterly broken (thanks to the guard); now
it works. Is anyone using the safe version??
1999-10-18 Evan Simpson <evan at 4-am.com>
* Eliminated bug which delayed stringification of printed values.
1999-10-08 Evan Simpson <evan at 4-am.com>
* Version 0.1.4
* Fixed mis-design noticed by Michel Pelletier, and refactored
MakeFunction. Now both kinds of Python Method have the bugfix
from 0.1.3, and shouldn't provoke a transaction when called.
1999-10-07 Evan Simpson <evan at 4-am.com>
* Version 0.1.3
* Fixed parameter bug with 'self' and no defaults
1999-09-24 Evan Simpson <evan at 4-am.com>
* Version 0.1.2
* Added WebDAV/FTP access code donated by Michel Pelletier
* Made parameters part of WebDAV/FTP text
* Eliminated initialization of globals to None
* Added 'global_exists' global function instead
* Killed bug with unused parameters
* Put switch in Guarded.py to allow both regular and
dangerous (XXX) PythonMethods to live side-by-side.
This means that people who patched version 0.1.1
will have to re-create any unsafe PMs they use (Sorry).
1999-09-10 Evan Simpson <evan at 4-am.com>
* Version 0.1.1
* Incorporated DT_Util builtins and guards
* Fixed direct access via URL
* Fixed methodAdd.dtml
* rstrip function body
* Major changes to zbytecodehacks
=== Added File Products/PythonMethod/COPYRIGHT.txt ===
This software is released under the following Wide-Open Source licence:
Copyright (c) 1999 Evan Simpson
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Author nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
=== Added File Products/PythonMethod/Guarded.py ===
from zbytecodehacks.VSExec import SafeBlock, GuardedOps, UntupleFunction
from DocumentTemplate.VSEval import careful_mul
from DocumentTemplate.DT_Util import TemplateDict, test
from DocumentTemplate.DT_Var import special_formats
safefuncs = TemplateDict()
safebin = safefuncs.__class__.__dict__.copy()
for k, v in safebin.items():
if type(v)==type(test):
safebin[k] = getattr(safefuncs, k)
safebin['special_formats'] = special_formats
class Guard:
mul = careful_mul
theGuard = Guard()
class GuardedBlock(SafeBlock):
Mungers = SafeBlock.Mungers + [GuardedOps(theGuard)]
# BEWARE OF THE LEOPARD!
# Set 'do_XXX' true to allow creation of XXXPythonMethods
# and ADD A MASSIVE GAPING SECURITY HOLE to Zope.
# DON'T DO THIS unless you use secure connections for ALL OF
# YOUR ADMINISTRATION or are RECKLESS and/or FEARLESS.
# Even if you DON'T create ANY XXXPythonMethods, just turning this
# on will PUT YOU AT RISK BIGTIME!
do_XXX = 0
if do_XXX:
from zbytecodehacks.VSExec import CodeBlock, Printing
class UnGuardedBlock(CodeBlock):
Mungers = [Printing]
=== Added File Products/PythonMethod/PythonMethod.py ===
"""Python Method Product
This product provides support for internal methods, which allow
safe implementation in a large Python subset.
"""
__version__='$Revision: 1.1 $'[11:-2]
from Globals import MessageDialog, HTMLFile, package_home
import sys, os, traceback, re
from OFS.SimpleItem import pretty_tb, SimpleItem
from DateTime.DateTime import DateTime
from string import join, rstrip, split
import Guarded
class AnObject:
def __init__(self, **kw):
self.__dict__.update(kw)
_www = os.path.join(package_home(globals()), 'www')
manage_addPythonMethodForm=HTMLFile('methodAdd', _www)
def manage_addPythonMethod(self, id, title, params, body, REQUEST=None):
"""Add an internal method to a folder
In addition to the standard Zope object-creation arguments,
'id' and title, the following arguments are defined:
params -- A standard Python parameter list.
body -- The text of the Python function definition.
"""
it = PythonMethod(id, title, params, body)
self._setObject(id, it)
return self.manage_main(self, REQUEST)
class PythonMethod(SimpleItem):
"""Web-callable functions written in a safe subset of Python.
The function may include standard python code, so long as it does
not assign to qualified names ([], .foo, ()), reference names
beginning with an underscore, or attempt to use the "del", "exec",
or "import" statements.
"""
meta_type='Python Method'
_proxy_roles = ()
index_html = None
_params = _body = None
manage_options = (
{'label':'Edit', 'action':'manage_main'},
{'label':'Try It', 'action':''},
{'label':'Proxy', 'action':'manage_proxyForm'},
{'label':'Security', 'action':'manage_access'},
)
__ac_permissions__ = (
('View management screens', ('manage_main',)),
('Change Python Methods', ('manage_edit',)),
('Change proxy roles', ('manage_proxyForm', 'manage_proxy')),
('View', ('__call__','')),
)
def __init__(self, id, title, params, body):
self.id = id
self.manage_edit(title, params, body)
manage = manage_main = HTMLFile('methodEdit', _www)
manage_proxyForm = HTMLFile('methodProxy', _www)
def manage_edit(self, title, params, body, height=None, width=None,
dtpref_cols='50', dtpref_rows='20', REQUEST=None):
"""Change the method
See the description of manage_addPythonMethod for a
description of the arguments 'params' and 'body'.
"""
self._validateProxy(REQUEST)
if height is not None or width is not None:
return self._er(title, params, body, height, width, dtpref_cols,
dtpref_rows, REQUEST)
self.title = title
if type(body) is not type(''):
body = body.read()
if self._params <> params or self._body <> body:
self._params = params
self._body = rstrip(body)
self.makeFunction(1)
if REQUEST:
message = "Content changed."
if self.warnings:
message = ("<strong>Warning:</strong> <i>%s</i>"
% join(self.warnings, '<br>'))
return self.manage_main(self, REQUEST, manage_tabs_message=message)
def _er(self, title, params, body, height, width, dtpref_cols,
dtpref_rows, REQUEST):
szch = {'+': 5, '-': -5, None: 0}
try: rows = int(height)
except: rows = max(1, int(dtpref_rows) + szch.get(height, 0))
try: cols = int(width)
except: cols = max(40, int(dtpref_cols) + szch.get(width, 0))
e = (DateTime('GMT') + 365).rfc822()
resp = REQUEST['RESPONSE']
resp.setCookie('dtpref_rows',str(rows),path='/',expires=e)
resp.setCookie('dtpref_cols',str(cols),path='/',expires=e)
return self.manage_main(self, REQUEST, title=title, params=params,
body=body, dtpref_cols=cols, dtpref_rows=rows)
def _checkCBlock(self, MakeBlock):
blk = MakeBlock(self.id, self._params, self._body)
self.errors, self.warnings = blk.errors, blk.warnings
if blk.errors:
if hasattr(self, '_v_f'): del self._v_f
self.func_defaults = ()
self.func_code = AnObject(co_varnames = (), co_argcount=0)
else:
self._t = blk.t
def _newfun(self, compiled, g, **kws):
from Guarded import UntupleFunction
self._v_f = f = apply(UntupleFunction, (self._t, g), kws)
fc = f.func_code
if compiled:
self.func_defaults=f.func_defaults
self.func_code=AnObject(co_varnames=fc.co_varnames,
co_argcount=fc.co_argcount)
fdefs = (f.func_defaults and len(f.func_defaults)) or 0
self._v_selfish = (fc.co_varnames and fc.co_varnames[0]=='self' and
(fc.co_argcount - fdefs - 1))
return f
def makeFunction(self, compile=0):
from Guarded import GuardedBlock, safefuncs, theGuard, safebin
if compile:
self._checkCBlock(GuardedBlock)
if self.errors:
raise "Python Method Error", join(self.errors, '\n')
return self._newfun(compile, {'$guard': theGuard},
__builtins__=safebin, _=safefuncs)
def __call__(self, *args, **kw):
"""Call a Python Method
Calling a Python Method is an actual function invocation.
If:
- The supplied number of arguments is one less than the
required number of arguments, and
- The name of the function's first argument is 'self'.
then the URL parent of the object is supplied as the
first argument.
"""
if hasattr(self, '_v_f'):
f = self._v_f
else: f = self.makeFunction()
__traceback_info__=args, kw, self.func_defaults
try:
return apply(f, args, kw)
except TypeError, v:
tb=sys.exc_traceback
try:
if self._v_selfish == len(args):
return apply(f,(self.aq_parent.this(),)+args,kw)
raise TypeError, v, tb
finally: tb=None
def manage_haveProxy(self,r): return r in self._proxy_roles
def _validateProxy(self, request, roles=None):
if roles is None: roles=self._proxy_roles
if not roles: return
user=u=request.get('AUTHENTICATED_USER',None)
if user is not None:
user=user.hasRole
for r in roles:
if r and not user(None, (r,)):
user=None
break
if user is not None: return
raise 'Forbidden', ('You are not authorized to change <em>%s</em> '
'because you do not have proxy roles.\n<!--%s, %s-->'
% (self.id, u, roles))
def manage_proxy(self, roles=(), REQUEST=None):
"Change Proxy Roles"
self._validateProxy(REQUEST, roles)
self._validateProxy(REQUEST)
self._proxy_roles=tuple(roles)
if REQUEST: return MessageDialog(
title ='Success!',
message='Your changes have been saved',
action ='manage_main')
def PUT(self, REQUEST, RESPONSE):
""" Handle HTTP PUT requests """
self.dav__init(REQUEST, RESPONSE)
body=REQUEST.get('BODY', '')
self._validateProxy(REQUEST)
m = re.match('\s*<params>(.*)</params>\s*\n', body, re.I)
if m:
self._params = m.group(1)
body = body[m.end():]
self._body = rstrip(body)
self.makeFunction(1)
RESPONSE.setStatus(204)
return RESPONSE
def manage_FTPget(self):
"Get source for FTP download"
return '<params>%s</params>\n%s' % (self._params, self._body)
def params(self): return self._params
def body(self): return self._body
def get_size(self): return len(self._body)
getSize = get_size
def PrincipiaSearchSource(self):
"Support for searching - the document's contents are searched."
return "%s\n%s" % (self._params, self._body)
def document_src(self, REQUEST, RESPONSE):
"""Return unprocessed document source."""
m = re.search('^[ ]+', self._body, re.M)
if m: prefix = ' ' * len(m.group(0))
else: prefix = ' ' * 4
body = join(split(self._body, '\n'), '\n%s' % prefix)
RESPONSE.setHeader('Content-Type', 'text/plain')
return "def %s(%s):\n%s%s" % (self.id, self._params, prefix, body)
def __bobo_traverse__(self, REQUEST, sub):
"""Collect direct traversal subpath if we have a parameter for it."""
vname = 'traverse_subpath'
noaq = self.aq_explicit
if hasattr(noaq, sub):
return getattr(self, sub)
varnames = noaq.func_code.co_varnames
if not (varnames and vname in varnames):
REQUEST.RESPONSE.notFoundError("%s\n%s" % (REQUEST.URL, sub))
subpath = REQUEST.other.get(vname, [])
subpath.append(sub)
REQUEST.set(vname, subpath)
return self
if Guarded.do_XXX:
class XXXPythonMethod(PythonMethod):
"""Unsafe version of PythonMethod
No restrictions, all normal builtins, unlimited import. The only thing
funky is the same print-command interception as normal PMs.
"""
meta_type='XXX Python Method'
def makeFunction(self, compile=0):
from Guarded import UnGuardedBlock, safefuncs
if compile:
self._checkCBlock(UnGuardedBlock)
if self.errors:
raise "XXX Python Method Error", join(self.errors, '\n')
return self._newfun(compile, {}, __builtins__=__builtins__,
_=safefuncs)
manage_addXXXPythonMethodForm=HTMLFile('XXXmethodAdd', _www)
def manage_addXXXPythonMethod(self, id, title, params, body, REQUEST=None):
"""Add an internal method to a folder
In addition to the standard Zope object-creation arguments,
'id' and title, the following arguments are defined:
params -- A standard Python parameter list.
body -- The text of the Python function definition.
"""
it = XXXPythonMethod(id, title, params, body)
self._setObject(id, it)
return self.manage_main(self, REQUEST)
=== Added File Products/PythonMethod/README.txt ===
Python Methods
The Python Method product provides support for internal Python
methods, exposing them as callable objects within the Zope
environment.
=== Added File Products/PythonMethod/__init__.py ===
__doc__='''PythonMethod Product'''
__version__='$Revision: 1.1 $'[11:-2]
import PythonMethod
def initialize(context):
context.registerClass(instance_class=PythonMethod.PythonMethod,
constructors=(PythonMethod.manage_addPythonMethodForm,
PythonMethod.manage_addPythonMethod),
icon='www/pymethod.gif')
import Guarded
if Guarded.do_XXX:
context.registerClass(instance_class=PythonMethod.XXXPythonMethod,
constructors=(PythonMethod.manage_addXXXPythonMethodForm,
PythonMethod.manage_addXXXPythonMethod),
icon='www/xpymethod.gif')
=== Added File Products/PythonMethod/version.txt ===
PythonMethod-0-1-7
More information about the zopeorg-checkins
mailing list