Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
6429477d
Commit
6429477d
authored
Nov 30, 2000
by
Evan Simpson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial checkin
parent
955f0de2
Changes
48
Hide whitespace changes
Inline
Side-by-side
Showing
48 changed files
with
6085 additions
and
0 deletions
+6085
-0
lib/python/Products/PythonScripts/Bindings.py
lib/python/Products/PythonScripts/Bindings.py
+351
-0
lib/python/Products/PythonScripts/CHANGES.txt
lib/python/Products/PythonScripts/CHANGES.txt
+77
-0
lib/python/Products/PythonScripts/Extensions/RemotePS.py
lib/python/Products/PythonScripts/Extensions/RemotePS.py
+20
-0
lib/python/Products/PythonScripts/Guarded.py
lib/python/Products/PythonScripts/Guarded.py
+273
-0
lib/python/Products/PythonScripts/ModuleSecurity.py
lib/python/Products/PythonScripts/ModuleSecurity.py
+108
-0
lib/python/Products/PythonScripts/PythonScript.py
lib/python/Products/PythonScripts/PythonScript.py
+421
-0
lib/python/Products/PythonScripts/README.txt
lib/python/Products/PythonScripts/README.txt
+6
-0
lib/python/Products/PythonScripts/Script.py
lib/python/Products/PythonScripts/Script.py
+143
-0
lib/python/Products/PythonScripts/__init__.py
lib/python/Products/PythonScripts/__init__.py
+101
-0
lib/python/Products/PythonScripts/standard.py
lib/python/Products/PythonScripts/standard.py
+123
-0
lib/python/Products/PythonScripts/version.txt
lib/python/Products/PythonScripts/version.txt
+1
-0
lib/python/Products/PythonScripts/www/pyScriptAdd.dtml
lib/python/Products/PythonScripts/www/pyScriptAdd.dtml
+27
-0
lib/python/Products/PythonScripts/www/pyScriptEdit.dtml
lib/python/Products/PythonScripts/www/pyScriptEdit.dtml
+55
-0
lib/python/Products/PythonScripts/www/pyScriptProxy.dtml
lib/python/Products/PythonScripts/www/pyScriptProxy.dtml
+53
-0
lib/python/Products/PythonScripts/www/pyScriptUpload.dtml
lib/python/Products/PythonScripts/www/pyScriptUpload.dtml
+35
-0
lib/python/Products/PythonScripts/www/pyscript.gif
lib/python/Products/PythonScripts/www/pyscript.gif
+0
-0
lib/python/Products/PythonScripts/www/scriptBindings.dtml
lib/python/Products/PythonScripts/www/scriptBindings.dtml
+89
-0
lib/python/Products/PythonScripts/www/scriptTry.dtml
lib/python/Products/PythonScripts/www/scriptTry.dtml
+30
-0
lib/python/Products/PythonScripts/zbytecodehacks/ChangeLog
lib/python/Products/PythonScripts/zbytecodehacks/ChangeLog
+112
-0
lib/python/Products/PythonScripts/zbytecodehacks/Makefile
lib/python/Products/PythonScripts/zbytecodehacks/Makefile
+18
-0
lib/python/Products/PythonScripts/zbytecodehacks/README
lib/python/Products/PythonScripts/zbytecodehacks/README
+38
-0
lib/python/Products/PythonScripts/zbytecodehacks/TODO
lib/python/Products/PythonScripts/zbytecodehacks/TODO
+1
-0
lib/python/Products/PythonScripts/zbytecodehacks/VSExec.py
lib/python/Products/PythonScripts/zbytecodehacks/VSExec.py
+583
-0
lib/python/Products/PythonScripts/zbytecodehacks/__init__.py
lib/python/Products/PythonScripts/zbytecodehacks/__init__.py
+10
-0
lib/python/Products/PythonScripts/zbytecodehacks/attr_freeze.py
...thon/Products/PythonScripts/zbytecodehacks/attr_freeze.py
+58
-0
lib/python/Products/PythonScripts/zbytecodehacks/closure.py
lib/python/Products/PythonScripts/zbytecodehacks/closure.py
+139
-0
lib/python/Products/PythonScripts/zbytecodehacks/code_editor.py
...thon/Products/PythonScripts/zbytecodehacks/code_editor.py
+385
-0
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/Makefile
...n/Products/PythonScripts/zbytecodehacks/code_gen/Makefile
+3
-0
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/__init__.py
...roducts/PythonScripts/zbytecodehacks/code_gen/__init__.py
+3
-0
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/op_execute_methods
.../PythonScripts/zbytecodehacks/code_gen/op_execute_methods
+138
-0
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/opexfuncread.py
...cts/PythonScripts/zbytecodehacks/code_gen/opexfuncread.py
+25
-0
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/regen
...thon/Products/PythonScripts/zbytecodehacks/code_gen/regen
+4
-0
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/write_ops.py
...oducts/PythonScripts/zbytecodehacks/code_gen/write_ops.py
+122
-0
lib/python/Products/PythonScripts/zbytecodehacks/common.py
lib/python/Products/PythonScripts/zbytecodehacks/common.py
+54
-0
lib/python/Products/PythonScripts/zbytecodehacks/cyclehandle.py
...thon/Products/PythonScripts/zbytecodehacks/cyclehandle.py
+54
-0
lib/python/Products/PythonScripts/zbytecodehacks/dbc.py
lib/python/Products/PythonScripts/zbytecodehacks/dbc.py
+251
-0
lib/python/Products/PythonScripts/zbytecodehacks/find_function_call.py
...oducts/PythonScripts/zbytecodehacks/find_function_call.py
+67
-0
lib/python/Products/PythonScripts/zbytecodehacks/iif.py
lib/python/Products/PythonScripts/zbytecodehacks/iif.py
+29
-0
lib/python/Products/PythonScripts/zbytecodehacks/inline.py
lib/python/Products/PythonScripts/zbytecodehacks/inline.py
+129
-0
lib/python/Products/PythonScripts/zbytecodehacks/label.py
lib/python/Products/PythonScripts/zbytecodehacks/label.py
+40
-0
lib/python/Products/PythonScripts/zbytecodehacks/macro.py
lib/python/Products/PythonScripts/zbytecodehacks/macro.py
+211
-0
lib/python/Products/PythonScripts/zbytecodehacks/macros.py
lib/python/Products/PythonScripts/zbytecodehacks/macros.py
+68
-0
lib/python/Products/PythonScripts/zbytecodehacks/opbases.py
lib/python/Products/PythonScripts/zbytecodehacks/opbases.py
+94
-0
lib/python/Products/PythonScripts/zbytecodehacks/ops.py
lib/python/Products/PythonScripts/zbytecodehacks/ops.py
+1086
-0
lib/python/Products/PythonScripts/zbytecodehacks/rationalize.py
...thon/Products/PythonScripts/zbytecodehacks/rationalize.py
+281
-0
lib/python/Products/PythonScripts/zbytecodehacks/tailr.py
lib/python/Products/PythonScripts/zbytecodehacks/tailr.py
+75
-0
lib/python/Products/PythonScripts/zbytecodehacks/version
lib/python/Products/PythonScripts/zbytecodehacks/version
+1
-0
lib/python/Products/PythonScripts/zbytecodehacks/xapply.py
lib/python/Products/PythonScripts/zbytecodehacks/xapply.py
+93
-0
No files found.
lib/python/Products/PythonScripts/Bindings.py
0 → 100644
View file @
6429477d
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in 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. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED 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 DIGITAL CREATIONS OR ITS
# 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.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
Globals
from
Globals
import
Persistent
,
HTMLFile
,
package_home
from
DocumentTemplate.DT_Util
import
TemplateDict
from
string
import
join
,
strip
import
re
import
os
_www
=
os
.
path
.
join
(
package_home
(
globals
()),
'www'
)
defaultBindings
=
{
'name_context'
:
'context'
,
'name_container'
:
'self'
,
'name_m_self'
:
'm_self'
,
'name_ns'
:
''
,
'name_subpath'
:
'traverse_subpath'
}
_marker
=
[]
# Create a new marker
class
NameAssignments
:
# Note that instances of this class are intended to be immutable
# and persistent but not inherit from ExtensionClass.
_exprs
=
((
'name_context'
,
'self.aq_parent'
),
(
'name_container'
,
'self.aq_inner.aq_parent'
),
(
'name_m_self'
,
'self'
),
(
'name_ns'
,
'self._getNamespace(caller_namespace, kw)'
),
(
'name_subpath'
,
'self._getTraverseSubpath()'
),
)
_isLegalName
=
re
.
compile
(
'_$|[a-zA-Z][a-zA-Z0-9_]*$'
).
match
_asgns
=
{}
__allow_access_to_unprotected_subobjects__
=
1
def
__init__
(
self
,
mapping
):
# mapping is presumably the REQUEST or compatible equivalent.
# Note that we take care not to store expression texts in the ZODB.
asgns
=
{}
_isLegalName
=
self
.
_isLegalName
for
name
,
expr
in
self
.
_exprs
:
if
mapping
.
has_key
(
name
):
assigned_name
=
strip
(
mapping
[
name
])
if
not
assigned_name
:
continue
if
not
_isLegalName
(
assigned_name
):
raise
ValueError
,
(
'"%s" is not a valid variable name.'
%
assigned_name
)
asgns
[
name
]
=
assigned_name
self
.
_asgns
=
asgns
def
isAnyNameAssigned
(
self
):
if
len
(
self
.
_asgns
)
>
0
:
return
1
return
0
def
isNameAssigned
(
self
,
name
):
return
self
.
_asgns
.
has_key
(
name
)
def
getAssignedName
(
self
,
name
,
default
=
_marker
):
val
=
self
.
_asgns
.
get
(
name
,
default
)
if
val
is
_marker
:
raise
KeyError
,
name
return
val
def
getAssignedNamesInOrder
(
self
):
# Returns the assigned names in the same order as that of
# self._exprs.
rval
=
[]
asgns
=
self
.
_asgns
for
name
,
expr
in
self
.
_exprs
:
if
asgns
.
has_key
(
name
):
assigned_name
=
asgns
[
name
]
rval
.
append
(
assigned_name
)
return
rval
def
_generateCodeBlock
(
self
,
bindtext
,
assigned_names
):
# Returns a tuple: exec-able code that can compute the value of
# the bindings and eliminate clashing keyword arguments,
# and the number of names bound.
text
=
[
'bound_data.append(%s)
\
n
'
%
bindtext
]
for
assigned_name
in
assigned_names
:
text
.
append
(
'if kw.has_key("%s"):
\
n
'
%
assigned_name
)
text
.
append
(
' del kw["%s"]
\
n
'
%
assigned_name
)
codetext
=
join
(
text
,
''
)
return
(
compile
(
codetext
,
'<string>'
,
'exec'
),
len
(
assigned_names
))
def
_createCodeBlockForMapping
(
self
):
# Generates a code block which generates the "bound_data"
# variable and removes excessive arguments from the "kw"
# variable. bound_data will be a mapping, for use as a
# global namespace.
exprtext
=
[]
assigned_names
=
[]
asgns
=
self
.
_asgns
for
name
,
expr
in
self
.
_exprs
:
if
asgns
.
has_key
(
name
):
assigned_name
=
asgns
[
name
]
assigned_names
.
append
(
assigned_name
)
exprtext
.
append
(
'"%s":%s,'
%
(
assigned_name
,
expr
))
text
=
'{%s}'
%
join
(
exprtext
,
''
)
return
self
.
_generateCodeBlock
(
text
,
assigned_names
)
def
_createCodeBlockForTuple
(
self
,
argNames
):
# Generates a code block which generates the "bound_data"
# variable and removes excessive arguments from the "kw"
# variable. bound_data will be a tuple, for use as
# positional arguments.
assigned_names
=
[]
exprtext
=
[]
asgns
=
self
.
_asgns
for
argName
in
argNames
:
passedLastBoundArg
=
1
for
name
,
expr
in
self
.
_exprs
:
# Provide a value for the available exprs.
if
asgns
.
has_key
(
name
):
assigned_name
=
asgns
[
name
]
if
assigned_name
==
argName
:
# The value for this argument will be filled in.
exprtext
.
append
(
'%s,'
%
expr
)
assigned_names
.
append
(
assigned_name
)
passedLastBoundArg
=
0
break
if
passedLastBoundArg
:
# Found last of bound args.
break
text
=
'(%s)'
%
join
(
exprtext
,
''
)
return
self
.
_generateCodeBlock
(
text
,
assigned_names
)
class
Bindings
(
Persistent
):
manage_options
=
(
{
'label'
:
'Bindings'
,
'action'
:
'ZBindingsHTML_editForm'
},
)
__ac_permissions__
=
(
(
'View management screens'
,
(
'ZBindingsHTML_editForm'
,
'getBindingAssignments'
,)),
(
'Change Python Scripts'
,
(
'ZBindingsHTML_editAction'
,
'ZBindings_edit'
)),
)
ZBindingsHTML_editForm
=
HTMLFile
(
'scriptBindings'
,
_www
)
def
ZBindings_edit
(
self
,
mapping
):
names
=
self
.
_setupBindings
(
mapping
)
self
.
_prepareBindCode
()
self
.
_editedBindings
()
def
ZBindingsHTML_editAction
(
self
,
REQUEST
):
'''Changes binding names.
'''
self
.
ZBindings_edit
(
REQUEST
)
message
=
"Bindings changed."
return
self
.
manage_main
(
self
,
REQUEST
,
manage_tabs_message
=
message
)
def
_editedBindings
(
self
):
# Override to receive notification when the bindings are edited.
pass
def
_setupBindings
(
self
,
names
=
{}):
self
.
_bind_names
=
names
=
NameAssignments
(
names
)
return
names
def
getBindingAssignments
(
self
):
if
not
hasattr
(
self
,
'_bind_names'
):
self
.
_setupBindings
()
return
self
.
_bind_names
def
__before_publishing_traverse__
(
self
,
self2
,
request
):
path
=
request
[
'TraversalRequestNameStack'
]
names
=
self
.
getBindingAssignments
()
if
(
not
names
.
isNameAssigned
(
'name_subpath'
)
or
(
path
and
hasattr
(
self
.
aq_explicit
,
path
[
-
1
]))
):
return
subpath
=
path
[:]
path
[:]
=
[]
subpath
.
reverse
()
request
.
set
(
'traverse_subpath'
,
subpath
)
def
_createBindCode
(
self
,
names
):
return
names
.
_createCodeBlockForMapping
()
def
_prepareBindCode
(
self
):
# Creates:
# - a code block that quickly generates "bound_data" and
# modifies the "kw" variable.
# - a count of the bound arguments.
# Saves them in _v_bindcode and _v_bindcount.
# Returns .
names
=
self
.
getBindingAssignments
()
if
names
.
isAnyNameAssigned
():
bindcode
,
bindcount
=
self
.
_createBindCode
(
names
)
else
:
bindcode
,
bindcount
=
None
,
0
self
.
_v_bindcode
=
bindcode
self
.
_v_bindcount
=
bindcount
return
bindcode
def
_getBindCount
(
self
):
bindcount
=
getattr
(
self
,
'_v_bindcount'
,
_marker
)
if
bindcount
is
_marker
:
self
.
_prepareBindCode
()
bindcount
=
self
.
_v_bindcount
return
bindcount
def
_getTraverseSubpath
(
self
):
# Utility for bindcode.
if
hasattr
(
self
,
'REQUEST'
):
return
self
.
REQUEST
.
other
.
get
(
'traverse_subpath'
,
[])
else
:
return
[]
def
_getNamespace
(
self
,
caller_namespace
,
kw
):
# Utility for bindcode.
if
caller_namespace
is
None
:
# Try to get the caller's namespace by scanning
# the keyword arguments for an argument with the
# same name as the assigned name for name_ns.
names
=
self
.
getBindingAssignments
()
assigned_name
=
names
.
getAssignedName
(
'name_ns'
)
caller_namespace
=
kw
.
get
(
assigned_name
,
None
)
# Create a local namespace.
my_namespace
=
TemplateDict
()
if
caller_namespace
is
not
None
:
# Include the caller's namespace.
my_namespace
.
_push
(
caller_namespace
)
return
my_namespace
def
__call__
(
self
,
*
args
,
**
kw
):
'''Calls the script.
'''
return
self
.
_bindAndExec
(
args
,
kw
,
None
)
def
__render_with_namespace__
(
self
,
namespace
):
'''Calls the script with the specified namespace.'''
namevals
=
{}
# Try to find unbound parameters in the namespace, if the
# namespace is bound.
if
self
.
getBindingAssignments
().
isNameAssigned
(
'name_ns'
):
for
name
in
self
.
func_code
.
co_varnames
:
try
:
namevals
[
name
]
=
namespace
[
name
]
except
KeyError
:
pass
return
self
.
_bindAndExec
((),
namevals
,
namespace
)
render
=
__call__
def
_bindAndExec
(
self
,
args
,
kw
,
caller_namespace
):
'''Prepares the bound information and calls _exec(), possibly
with a namespace.
'''
bindcode
=
getattr
(
self
,
'_v_bindcode'
,
_marker
)
if
bindcode
is
_marker
:
bindcode
=
self
.
_prepareBindCode
()
bound_data
=
None
if
bindcode
is
not
None
:
bound_data
=
[]
exec
bindcode
bound_data
=
bound_data
[
0
]
return
self
.
_exec
(
bound_data
,
args
,
kw
)
Globals
.
default__class_init__
(
Bindings
)
lib/python/Products/PythonScripts/CHANGES.txt
0 → 100644
View file @
6429477d
1999-12-13 Evan Simpson <evan@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@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@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@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@4-am.com>
* Eliminated bug which delayed stringification of printed values.
1999-10-08 Evan Simpson <evan@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@4-am.com>
* Version 0.1.3
* Fixed parameter bug with 'self' and no defaults
1999-09-24 Evan Simpson <evan@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@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
lib/python/Products/PythonScripts/Extensions/RemotePS.py
0 → 100644
View file @
6429477d
''' RemotePS.py
External Method that allows you to remotely (via XML-RPC, for instance)
execute restricted Python code.
For example, create an External Method 'restricted_exec' in your Zope
root, and you can remotely call:
foobarsize = s.foo.bar.restricted_exec('len(context.objectIds())')
'''
from
Products.PythonScripts.PythonScript
import
PythonScript
from
string
import
join
def
restricted_exec
(
self
,
body
,
varmap
=
None
):
ps
=
PythonScript
(
'temp'
)
if
varmap
is
None
:
varmap
=
{}
ps
.
ZPythonScript_edit
(
join
(
varmap
.
keys
(),
','
),
body
)
return
apply
(
ps
.
__of__
(
self
),
varmap
.
values
())
lib/python/Products/PythonScripts/Guarded.py
0 → 100644
View file @
6429477d
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in 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. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED 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 DIGITAL CREATIONS OR ITS
# 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.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
from
zbytecodehacks.VSExec
import
SafeBlock
,
GuardedBinaryOps
,
\
UntupleFunction
,
RedirectWrites
,
WriteGuard
,
RedirectReads
,
ReadGuard
,
\
LoopLimits
,
bind
from
DocumentTemplate.VSEval
import
careful_mul
from
DocumentTemplate.DT_Util
import
TemplateDict
,
\
careful_pow
,
d
,
ValidationError
from
DocumentTemplate.DT_Var
import
special_formats
from
AccessControl
import
getSecurityManager
,
getModuleSecurity
import
standard
standard
.
__allow_access_to_unprotected_subobjects__
=
1
safefuncs
=
TemplateDict
()
safebin
=
{}
for
name
in
(
'None'
,
'abs'
,
'chr'
,
'divmod'
,
'float'
,
'hash'
,
'hex'
,
'int'
,
'len'
,
'max'
,
'min'
,
'oct'
,
'ord'
,
'round'
,
'str'
):
safebin
[
name
]
=
d
[
name
]
for
name
in
(
'range'
,
'pow'
,
'DateTime'
,
'test'
,
'namespace'
,
'render'
):
safebin
[
name
]
=
getattr
(
safefuncs
,
name
)
for
name
in
(
'ArithmeticError'
,
'AttributeError'
,
'EOFError'
,
'EnvironmentError'
,
'FloatingPointError'
,
'IOError'
,
'ImportError'
,
'IndexError'
,
'KeyError'
,
'LookupError'
,
'NameError'
,
'OSError'
,
'OverflowError'
,
'RuntimeError'
,
'StandardError'
,
'SyntaxError'
,
'TypeError'
,
'ValueError'
,
'ZeroDivisionError'
,
'apply'
,
'callable'
,
'cmp'
,
'complex'
,
'isinstance'
,
'issubclass'
,
'long'
,
'repr'
):
safebin
[
name
]
=
__builtins__
[
name
]
def
same_type
(
arg1
,
*
args
):
'''Compares the type of two or more objects.'''
base
=
getattr
(
arg1
,
'aq_base'
,
arg1
)
t
=
type
(
base
)
for
arg
in
args
:
argbase
=
getattr
(
arg
,
'aq_base'
,
arg
)
if
type
(
argbase
)
is
not
t
:
return
0
return
1
safebin
[
'same_type'
]
=
same_type
_marker
=
[]
# Create a new marker object.
def
aq_validate
(
*
args
):
return
apply
(
getSecurityManager
().
validate
,
args
[:
4
])
def
__careful_getattr__
(
inst
,
name
,
default
=
_marker
):
if
name
[:
1
]
!=
'_'
:
try
:
# Try to get the attribute normally so that we don't
# accidentally acquire when we shouldn't.
v
=
getattr
(
inst
,
name
)
# Filter out the objects we can't access.
if
hasattr
(
inst
,
'aq_acquire'
):
return
inst
.
aq_acquire
(
name
,
aq_validate
)
except
AttributeError
:
if
default
is
not
_marker
:
return
default
raise
if
getSecurityManager
().
validate
(
inst
,
inst
,
name
,
v
):
return
v
raise
ValidationError
,
name
safebin
[
'getattr'
]
=
__careful_getattr__
def
__careful_setattr__
(
object
,
name
,
value
):
setattr
(
WriteGuard
(
object
),
name
,
value
)
safebin
[
'setattr'
]
=
__careful_setattr__
def
__careful_delattr__
(
object
,
name
):
delattr
(
WriteGuard
(
object
),
name
)
safebin
[
'delattr'
]
=
__careful_delattr__
def
__careful_filter__
(
f
,
seq
,
skip_unauthorized
=
0
):
if
type
(
seq
)
is
type
(
''
):
return
filter
(
f
,
seq
)
v
=
getSecurityManager
().
validate
result
=
[]
a
=
result
.
append
for
el
in
seq
:
if
v
(
seq
,
seq
,
None
,
el
):
if
f
(
el
):
a
(
el
)
elif
not
skip_unauthorized
:
raise
ValidationError
,
'unauthorized access to element'
return
result
safebin
[
'filter'
]
=
__careful_filter__
def
__careful_list__
(
seq
):
if
type
(
seq
)
is
type
(
''
):
raise
TypeError
,
'cannot convert string to list'
return
list
(
seq
)
safebin
[
'list'
]
=
__careful_list__
def
__careful_tuple__
(
seq
):
if
type
(
seq
)
is
type
(
''
):
raise
TypeError
,
'cannot convert string to tuple'
return
tuple
(
seq
)
safebin
[
'tuple'
]
=
__careful_tuple__
def
__careful_map__
(
f
,
*
seqs
):
for
seq
in
seqs
:
if
type
(
seq
)
is
type
(
''
):
raise
TypeError
,
'cannot map a string'
return
apply
(
map
,
tuple
([
f
]
+
map
(
ReadGuard
,
seqs
)))
safebin
[
'map'
]
=
__careful_map__
import
sys
from
string
import
split
def
__careful_import__
(
mname
,
globals
=
{},
locals
=
{},
fromlist
=
None
):
mnameparts
=
split
(
mname
,
'.'
)
firstmname
=
mnameparts
[
0
]
validate
=
getSecurityManager
().
validate
module
=
load_module
(
None
,
None
,
mnameparts
,
validate
,
globals
,
locals
)
if
module
is
not
None
:
mtype
=
type
(
module
)
if
fromlist
is
None
:
fromlist
=
()
try
:
for
name
in
fromlist
:
if
name
==
'*'
:
raise
ImportError
,
(
'"from %s import *" is not allowed'
%
mname
)
v
=
getattr
(
module
,
name
,
None
)
if
v
is
None
:
v
=
load_module
(
module
,
mname
,
[
name
],
validate
,
globals
,
locals
)
if
not
validate
(
module
,
module
,
name
,
v
):
raise
"Unauthorized"
else
:
return
__import__
(
mname
,
globals
,
locals
,
fromlist
)
except
"Unauthorized"
:
raise
ImportError
,
(
'import of "%s" from "%s" is unauthorized'
%
(
name
,
mname
))
raise
ImportError
,
'import of "%s" is unauthorized'
%
mname
safebin
[
'__import__'
]
=
__careful_import__
def
load_module
(
module
,
mname
,
mnameparts
,
validate
,
globals
,
locals
):
modules
=
sys
.
modules
modsec
=
getModuleSecurity
()
while
mnameparts
:
nextname
=
mnameparts
.
pop
(
0
)
if
mname
is
None
:
mname
=
nextname
else
:
mname
=
'%s.%s'
%
(
mname
,
nextname
)
nextmodule
=
modules
.
get
(
mname
,
None
)
if
nextmodule
is
None
:
if
not
modsec
.
has_key
(
mname
):
return
__import__
(
mname
,
globals
,
locals
)
nextmodule
=
modules
[
mname
]
nextmodule
.
ZopeSecurity
=
modsec
[
mname
]
if
module
and
not
validate
(
module
,
module
,
nextname
,
nextmodule
):
return
module
=
nextmodule
return
module
class
Guard
:
mul
=
careful_mul
pow
=
careful_pow
theGuard
=
Guard
()
class
GuardedBlock
(
SafeBlock
):
Mungers
=
SafeBlock
.
Mungers
+
[
GuardedBinaryOps
(
theGuard
),
RedirectWrites
(),
RedirectReads
(),
LoopLimits
]
class
_ReadGuardWrapper
:
#def validate(self, *args):
# return apply(getSecurityManager().validate, args[:4])
def
__getattr__
(
self
,
name
):
ob
=
self
.
__dict__
[
'_ob'
]
return
__careful_getattr__
(
ob
,
name
)
def
__getitem__
(
self
,
i
):
ob
=
self
.
__dict__
[
'_ob'
]
v
=
ob
[
i
]
if
type
(
ob
)
is
type
(
''
):
return
v
if
getSecurityManager
().
validate
(
ob
,
ob
,
None
,
v
):
return
v
raise
ValidationError
,
'unauthorized access to element %s'
%
`i`
ReadGuard
=
bind
(
ReadGuard
,
Wrapper
=
_ReadGuardWrapper
)
lib/python/Products/PythonScripts/ModuleSecurity.py
0 → 100644
View file @
6429477d
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in 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. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED 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 DIGITAL CREATIONS OR ITS
# 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.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""Module Security module
"""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
AccessControl
class
ModuleSecurityInfo
:
#(AccessControl.ClassSecurityInfo):
def
__init__
(
self
,
module_name
=
None
):
if
module_name
is
not
None
:
moduleSecurity
[
module_name
]
=
self
def
stub
(
self
,
*
args
,
**
kwargs
):
pass
def
__getattr__
(
self
,
name
):
return
self
.
stub
moduleSecurity
=
{}
def
getModuleSecurity
():
return
moduleSecurity
AccessControl
.
getModuleSecurity
=
getModuleSecurity
AccessControl
.
ModuleSecurityInfo
=
ModuleSecurityInfo
lib/python/Products/PythonScripts/PythonScript.py
0 → 100644
View file @
6429477d
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in 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. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED 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 DIGITAL CREATIONS OR ITS
# 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.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""Python Scripts Product
This product provides support for Script objects containing restricted
Python code.
"""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
sys
,
os
,
traceback
,
re
from
Globals
import
MessageDialog
,
HTMLFile
,
package_home
import
AccessControl
,
OFS
,
Guarded
from
OFS.SimpleItem
import
SimpleItem
from
DateTime.DateTime
import
DateTime
from
string
import
join
,
strip
,
rstrip
,
split
,
replace
,
lower
from
urllib
import
quote
from
Bindings
import
Bindings
,
defaultBindings
from
Script
import
Script
from
AccessControl
import
getSecurityManager
from
OFS.History
import
Historical
,
html_diff
from
zLOG
import
LOG
,
ERROR
,
INFO
_www
=
os
.
path
.
join
(
package_home
(
globals
()),
'www'
)
manage_addPythonScriptForm
=
HTMLFile
(
'pyScriptAdd'
,
_www
)
def
manage_addPythonScript
(
self
,
id
,
REQUEST
=
None
):
"""Add a Python script to a folder.
"""
id
=
str
(
id
)
id
=
self
.
_setObject
(
id
,
PythonScript
(
id
))
if
REQUEST
is
not
None
:
try
:
u
=
self
.
DestinationURL
()
except
:
u
=
REQUEST
[
'URL1'
]
REQUEST
.
RESPONSE
.
redirect
(
'%s/%s/manage_main'
%
(
u
,
quote
(
id
)))
return
''
class
PythonScript
(
Script
,
Historical
):
"""Web-callable scripts written in a safe subset of Python.
The function may include standard python code, so long as it does
not attempt to use the "exec" statement or certain restricted builtins.
"""
meta_type
=
'Python Script'
_proxy_roles
=
()
_params
=
_body
=
''
manage_options
=
(
{
'label'
:
'Edit'
,
'action'
:
'ZPythonScriptHTML_editForm'
},
{
'label'
:
'Upload'
,
'action'
:
'ZPythonScriptHTML_uploadForm'
},
)
+
Bindings
.
manage_options
+
(
{
'label'
:
'Try It'
,
'action'
:
'ZScriptHTML_tryForm'
},
{
'label'
:
'Proxy'
,
'action'
:
'manage_proxyForm'
},
)
+
Historical
.
manage_options
+
SimpleItem
.
manage_options
__ac_permissions__
=
(
(
'View management screens'
,
(
'ZPythonScriptHTML_editForm'
,
'ZPythonScript_changePrefs'
,
'manage_main'
,
'ZScriptHTML_tryForm'
)),
(
'Change Python Scripts'
,
(
'ZPythonScript_edit'
,
'PUT'
,
'manage_FTPput'
,
'ZPythonScript_setTitle'
,
'ZPythonScriptHTML_upload'
,
'ZPythonScriptHTML_uploadForm'
,
'manage_historyCopy'
,
'manage_beforeHistoryCopy'
,
'manage_afterHistoryCopy'
)),
(
'Change proxy roles'
,
(
'manage_proxyForm'
,
'manage_proxy'
)),
(
'View'
,
(
'__call__'
,
''
,
'ZPythonScriptHTML_tryAction'
)),
)
def
__init__
(
self
,
id
):
self
.
id
=
id
self
.
ZBindings_edit
(
defaultBindings
)
self
.
_makeFunction
(
1
)
ZPythonScriptHTML_editForm
=
HTMLFile
(
'pyScriptEdit'
,
_www
)
manage
=
manage_main
=
ZPythonScriptHTML_editForm
manage_proxyForm
=
HTMLFile
(
'pyScriptProxy'
,
_www
)
ZScriptHTML_tryForm
=
HTMLFile
(
'scriptTry'
,
_www
)
ZPythonScriptHTML_uploadForm
=
HTMLFile
(
'pyScriptUpload'
,
_www
)
def
ZPythonScriptHTML_editAction
(
self
,
REQUEST
,
title
,
params
,
body
):
"""Change the script's main parameters."""
self
.
ZPythonScript_setTitle
(
title
)
self
.
ZPythonScript_edit
(
params
,
body
)
message
=
"Content changed."
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
)
def
ZPythonScript_setTitle
(
self
,
title
):
self
.
title
=
str
(
title
)
def
ZPythonScript_edit
(
self
,
params
,
body
):
self
.
_validateProxy
()
if
type
(
body
)
is
not
type
(
''
):
body
=
body
.
read
()
if
self
.
_params
<>
params
or
self
.
_body
<>
body
:
self
.
_params
=
str
(
params
)
self
.
_body
=
rstrip
(
body
)
self
.
_makeFunction
(
1
)
def
ZPythonScriptHTML_upload
(
self
,
REQUEST
,
file
=
''
):
"""Replace the body of the script with the text in file."""
if
type
(
file
)
is
not
type
(
''
):
file
=
file
.
read
()
self
.
_setText
(
file
)
message
=
'Content changed.'
return
self
.
ZPythonScriptHTML_editForm
(
self
,
REQUEST
,
manage_tabs_message
=
message
)
def
ZScriptHTML_tryParams
(
self
):
"""Parameters to test the script with."""
param_names
=
[]
for
name
in
split
(
self
.
_params
,
','
):
name
=
strip
(
name
)
if
name
and
name
[
0
]
!=
'*'
:
param_names
.
append
(
name
)
return
param_names
def
ZPythonScriptHTML_changePrefs
(
self
,
REQUEST
,
height
=
None
,
width
=
None
,
dtpref_cols
=
'50'
,
dtpref_rows
=
'20'
):
"""Change editing preferences."""
LOG
(
'PythonScript'
,
INFO
,
'Change prefs h: %s, w: %s, '
'cols: %s, rows: %s'
%
(
height
,
width
,
dtpref_cols
,
dtpref_rows
))
szchh
=
{
'Taller'
:
1
,
'Shorter'
:
-
1
,
None
:
0
}
szchw
=
{
'Wider'
:
5
,
'Narrower'
:
-
5
,
None
:
0
}
try
:
rows
=
int
(
height
)
except
:
rows
=
max
(
1
,
int
(
dtpref_rows
)
+
szchh
.
get
(
height
,
0
))
try
:
cols
=
int
(
width
)
except
:
cols
=
max
(
40
,
int
(
dtpref_cols
)
+
szchw
.
get
(
width
,
0
))
LOG
(
'PythonScript'
,
INFO
,
'to cols: %s, rows: %s'
%
(
cols
,
rows
))
e
=
(
DateTime
(
'GMT'
)
+
365
).
rfc822
()
setc
=
REQUEST
[
'RESPONSE'
].
setCookie
setc
(
'dtpref_rows'
,
str
(
rows
),
path
=
'/'
,
expires
=
e
)
setc
(
'dtpref_cols'
,
str
(
cols
),
path
=
'/'
,
expires
=
e
)
REQUEST
.
form
.
update
({
'dtpref_cols'
:
cols
,
'dtpref_rows'
:
rows
})
return
apply
(
self
.
manage_main
,
(
self
,
REQUEST
),
REQUEST
.
form
)
def
manage_historyCompare
(
self
,
rev1
,
rev2
,
REQUEST
,
historyComparisonResults
=
''
):
return
PythonScript
.
inheritedAttribute
(
'manage_historyCompare'
)(
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)
else:
# Waaa: triple-quoted strings will get indented too.
defblk = '
def
f
(
%
s
):
\
n
%
s
\
n
' % (params, replace(body, '
\
n
', '
\
n
'))
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
self._setFuncSignature((), (), 0)
else:
self._t = blk.t
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)
return f
def _makeFunction(self, allowSideEffect=0):
from Guarded import GuardedBlock, theGuard, safebin
from Guarded import WriteGuard, ReadGuard
if allowSideEffect:
self._checkCBlock(GuardedBlock)
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},
__builtins__=safebin)
def _editedBindings(self):
f = getattr(self, '
_v_f
', None)
if f is None:
return
self._makeFunction(1)
def _exec(self, globals, args, kw):
"""Call a Python Script
Calling a Python Script is an actual function invocation.
"""
f = getattr(self, '
_v_f
', None)
if f is None:
f = self._makeFunction()
__traceback_info__ = globals, args, kw, self.func_defaults
if globals is not None:
# Updating func_globals directly *should* be thread-safe.
f.func_globals.update(globals)
security=getSecurityManager()
security.addContext(self)
try:
return apply(f, args, kw)
finally:
security.removeContext(self)
def manage_haveProxy(self,r): return r in self._proxy_roles
def _validateProxy(self, roles=None):
if roles is None: roles=self._proxy_roles
if not roles: return
user=u=getSecurityManager().getUser()
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(roles)
self._validateProxy()
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)
self._setText(REQUEST.get('
BODY
', ''))
RESPONSE.setStatus(204)
return RESPONSE
manage_FTPput = PUT
def _setText(self, text):
self._validateProxy()
mdata = self._metadata_map()
st = 0
try:
while 1:
# Find the next non-empty line
m = _nonempty_line.search(text, st)
if not m:
# There were no non-empty body lines
body = ''
break
line = strip(m.group(0))
if line[:2] != '
##':
# We have found the first line of the body
body
=
text
[
m
.
start
(
0
):]
break
st
=
m
.
end
(
0
)
# Parse this header line
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
)
if
not
mdata
.
has_key
(
k
):
SyntaxError
,
'Unrecognized header line "%s"'
%
line
if
v
==
mdata
[
k
]:
# Unchanged value
continue
# Set metadata value
if
k
==
'title'
:
self
.
title
=
v
elif
k
==
'parameters'
:
self
.
_params
=
v
self
.
_body
=
rstrip
(
body
)
self
.
_makeFunction
(
1
)
except
:
LOG
(
self
.
meta_type
,
ERROR
,
'_setText failed'
,
error
=
sys
.
exc_info
())
raise
def
manage_FTPget
(
self
):
"Get source for FTP download"
self
.
REQUEST
.
RESPONSE
.
setHeader
(
'Content-Type'
,
'text/plain'
)
return
self
.
read
()
def
_metadata_map
(
self
):
return
{
'title'
:
self
.
title
,
'parameters'
:
self
.
_params
,
}
def
read
(
self
):
# Construct metadata header lines, indented the same as the body.
m
=
_first_indent
.
search
(
self
.
_body
)
if
m
:
prefix
=
m
.
group
(
0
)
+
'##'
else
:
prefix
=
'##'
hlines
=
[
'%s %s "%s"'
%
(
prefix
,
self
.
meta_type
,
self
.
id
)]
for
kv
in
self
.
_metadata_map
().
items
():
hlines
.
append
(
'%s=%s'
%
kv
)
hlines
.
append
(
''
)
return
join
(
hlines
,
'
\
n
'
+
prefix
)
+
'
\
n
'
+
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
=
None
,
RESPONSE
=
None
):
"""Return unprocessed document source."""
if
RESPONSE
is
not
None
:
RESPONSE
.
setHeader
(
'Content-Type'
,
'text/plain'
)
return
self
.
read
()
_first_indent
=
re
.
compile
(
'(?m)^ *(?! |$)'
)
_nonempty_line
=
re
.
compile
(
'(?m)^(.*
\
S.*)$
'
)
lib/python/Products/PythonScripts/README.txt
0 → 100644
View file @
6429477d
Python Scripts
The Python Scripts product provides support for restricted execution of
Python scripts, exposing them as callable objects within the Zope
environment.
lib/python/Products/PythonScripts/Script.py
0 → 100644
View file @
6429477d
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in 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. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED 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 DIGITAL CREATIONS OR ITS
# 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.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""Script module
This provides generic script support
"""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
os
from
Globals
import
package_home
,
HTMLFile
from
OFS.SimpleItem
import
SimpleItem
from
string
import
join
from
urllib
import
quote
from
Bindings
import
Bindings
class
FuncCode
:
def
__init__
(
self
,
varnames
,
argcount
):
self
.
co_varnames
=
varnames
self
.
co_argcount
=
argcount
def
__cmp__
(
self
,
other
):
if
other
is
None
:
return
1
try
:
return
cmp
((
self
.
co_argcount
,
self
.
co_varnames
),
(
other
.
co_argcount
,
other
.
co_varnames
))
except
:
return
1
_www
=
os
.
path
.
join
(
package_home
(
globals
()),
'www'
)
class
Script
(
SimpleItem
,
Bindings
):
"""Web-callable script mixin
"""
index_html
=
None
func_defaults
=
()
func_code
=
None
__ac_permissions__
=
(
(
'View management screens'
,
(
'ZScriptHTML_tryForm'
,)),
(
'View'
,
(
'__call__'
,
''
,
'ZPythonScriptHTML_tryAction'
)),
)
ZScriptHTML_tryForm
=
HTMLFile
(
'scriptTry'
,
_www
)
def
ZScriptHTML_tryAction
(
self
,
REQUEST
,
argvars
):
"""Apply the test parameters.
"""
vv
=
[]
for
argvar
in
argvars
:
vv
.
append
(
"%s=%s"
%
(
quote
(
argvar
.
name
),
quote
(
argvar
.
value
)))
raise
"Redirect"
,
"%s?%s"
%
(
REQUEST
[
'URL1'
],
join
(
vv
,
'&'
))
def
_setFuncSignature
(
self
,
defaults
,
varnames
,
argcount
):
# Generate a change only if we have to.
if
self
.
func_defaults
!=
defaults
:
self
.
func_defaults
=
defaults
code
=
FuncCode
(
varnames
,
argcount
)
if
self
.
func_code
!=
code
:
self
.
func_code
=
code
lib/python/Products/PythonScripts/__init__.py
0 → 100644
View file @
6429477d
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in 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. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED 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 DIGITAL CREATIONS OR ITS
# 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.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
__doc__
=
'''Python Scripts Product Initialization
$Id: __init__.py,v 1.1 2000/11/30 22:18:03 evan Exp $'''
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
import
ModuleSecurity
import
PythonScript
import
standard
__roles__
=
None
__allow_access_to_unprotected_subobjects__
=
1
def
initialize
(
context
):
context
.
registerClass
(
instance_class
=
PythonScript
.
PythonScript
,
constructors
=
(
PythonScript
.
manage_addPythonScriptForm
,
PythonScript
.
manage_addPythonScript
),
icon
=
'www/pyscript.gif'
)
lib/python/Products/PythonScripts/standard.py
0 → 100644
View file @
6429477d
##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in 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. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED 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 DIGITAL CREATIONS OR ITS
# 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.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""Python Scripts standard utility module
This module provides helpful functions and classes for use in Python
Scripts. It can be accessed from Python with the statement
"import Products.PythonScripts.standard"
"""
__version__
=
'$Revision: 1.1 $'
[
11
:
-
2
]
from
AccessControl
import
ModuleSecurityInfo
security
=
ModuleSecurityInfo
()
security
.
public
(
'special_formats'
)
from
DocumentTemplate.DT_Var
import
special_formats
from
Globals
import
HTML
from
AccessControl
import
getSecurityManager
security
.
public
(
'DTML'
)
class
DTML
(
HTML
):
"""DTML objects are DocumentTemplate.HTML objects that allow
dynamic, temporary creation of restricted DTML."""
def
__call__
(
self
,
client
=
None
,
REQUEST
=
{},
RESPONSE
=
None
,
**
kw
):
"""Render the DTML given a client object, REQUEST mapping,
Response, and key word arguments."""
security
=
getSecurityManager
()
security
.
addContext
(
self
)
try
:
return
apply
(
HTML
.
__call__
,
(
self
,
client
,
REQUEST
),
kw
)
finally
:
security
.
removeContext
(
self
)
def
validate
(
self
,
inst
,
parent
,
name
,
value
,
md
):
return
getSecurityManager
().
validate
(
inst
,
parent
,
name
,
value
)
lib/python/Products/PythonScripts/version.txt
0 → 100644
View file @
6429477d
PythonScripts-1-0-0
lib/python/Products/PythonScripts/www/pyScriptAdd.dtml
0 → 100644
View file @
6429477d
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html
lang=
"en"
>
<head>
<title>
Add Python Script
</title>
</head>
<body
bgcolor=
"#FFFFFF"
link=
"#000099"
vlink=
"#555555"
alink=
"#77003B"
>
<h2>
Add Python Script
</h2>
<P>
Python Scripts allow you to add functionality to Zope by writing
scripts in the Python programming language
that are exposed as callable Zope objects.
</P>
<form
action=
"&dtml-URL1;"
method=
"POST"
>
<input
type=
"hidden"
name=
"manage_addPythonScript:default_method"
value=
""
>
<p>
<strong>
ID:
</strong>
<input
type=
"text"
name=
"id"
size=
"20"
>
</p>
<p>
<input
type=
"submit"
value=
"Add and Edit"
name=
"addedit"
>
<input
type=
"submit"
value=
"Cancel"
name=
"manage_workspace:method"
>
</p>
</form>
</body>
</html>
lib/python/Products/PythonScripts/www/pyScriptEdit.dtml
0 → 100644
View file @
6429477d
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html
lang=
"en"
>
<head>
<title>
Edit
<dtml-var
title_or_id
></title>
</head>
<body
bgcolor=
"#ffffff"
link=
"#000099"
vlink=
"#555555"
alink=
"#77003b"
>
<dtml-var
manage_tabs
>
<form
action=
"&dtml-URL1;"
method=
"POST"
>
<input
type=
"hidden"
name=
":default_method"
value=
"ZPythonScriptHTML_changePrefs"
>
<table
cellspacing=
"2"
>
<tr>
<th
align=
"left"
valign=
"top"
><em>
Title
</em></th>
<td
align=
"left"
valign=
"top"
>
<input
type=
"text"
name=
"title"
size=
"50"
value=
"&dtml-title;"
>
</td>
</tr>
<tr>
<th
align=
"left"
><em>
Parameter
list
</em></th>
<td
align=
"left"
><input
name=
"params"
size=
"30"
value=
"&dtml-params;"
>
</td></tr>
<dtml-with
getBindingAssignments
>
<dtml-if
getAssignedNamesInOrder
>
<tr>
<th
align=
"left"
><em>
Bound
names
</em></th>
<td
align=
"left"
>
<dtml-in
getAssignedNamesInOrder
>
<dtml-var
sequence-item
html_quote
><dtml-unless
sequence-end
>
,
</dtml-unless>
</dtml-in>
</td></tr>
</dtml-if>
</dtml-with>
<tr>
<th
align=
"left"
valign=
"top"
><em>
Last
modified
</em></th>
<td
align=
"left"
valign=
"top"
><dtml-var
bobobase_modification_time
></td>
</tr>
</table>
<!-- style="width: 2em" -->
<b>
Text area
</b>
<input
name=
"height"
type=
"submit"
value=
"Taller"
>
<input
name=
"height"
type=
"submit"
value=
"Shorter"
>
<input
name=
"width"
type=
"submit"
value=
"Wider"
>
<input
name=
"width"
type=
"submit"
value=
"Narrower"
>
<br>
<textarea
name=
"body:text"
wrap=
"off"
style=
"width: 100%"
cols=
<dtml-var
dtpref_cols
html_quote
missing=
"50"
>
rows=
<dtml-var
dtpref_rows
html_quote
missing=
"20"
>
>
&dtml-body;
</textarea><br>
<input
name=
"ZPythonScriptHTML_editAction:method"
type=
"submit"
value=
"Save Changes"
>
</form>
</body>
</html>
lib/python/Products/PythonScripts/www/pyScriptProxy.dtml
0 → 100644
View file @
6429477d
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML
lang=
"en"
>
<HEAD>
<TITLE>
Edit
</TITLE>
</HEAD>
<BODY
BGCOLOR=
"#FFFFFF"
LINK=
"#000099"
VLINK=
"#555555"
>
<dtml-var
manage_tabs
>
<P>
Proxy roles allow you to control the access that a
Script has. Proxy roles replace the roles of the user who is executing
the Script. This can be used to both expand and limit
access to resources.
</P>
<P>
Use the form below to select which roles this Script will have.
</P>
<FORM
ACTION=
"manage_proxy"
METHOD=
"POST"
>
<TABLE
CELLSPACING=
"2"
>
<TR>
<TH
ALIGN=
"LEFT"
VALIGN=
"TOP"
>
Id
</TH>
<TD
ALIGN=
"LEFT"
VALIGN=
"TOP"
><dtml-var
id
></TD>
</TR>
<TR>
<TH
ALIGN=
"LEFT"
VALIGN=
"TOP"
><EM>
Title
</EM></TH>
<TD
ALIGN=
"LEFT"
VALIGN=
"TOP"
><dtml-var
title
></TD>
</TR>
<TR>
<TH
ALIGN=
"LEFT"
VALIGN=
"TOP"
>
Proxy Roles
</TH>
<TD
VALIGN=
"TOP"
>
<SELECT
NAME=
"roles:list"
SIZE=
"7"
MULTIPLE
>
<dtml-in
valid_roles
>
<dtml-if
expr=
"_vars['sequence-item'] != 'Shared'"
>
<OPTION
<
dtml-if
expr=
"manage_haveProxy(_vars['sequence-item'])"
>
SELECTED
</dtml-if>
>
<dtml-var
sequence-item
></OPTION>
</dtml-if>
</dtml-in
valid_roles
>
</SELECT>
</TD>
</TR>
<TR>
<TD></TD>
<TD>
<INPUT
NAME=
SUBMIT
TYPE=
"SUBMIT"
VALUE=
"Change"
>
</TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
lib/python/Products/PythonScripts/www/pyScriptUpload.dtml
0 → 100644
View file @
6429477d
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML
lang=
"en"
>
<HEAD>
<TITLE>
Upload
</TITLE>
</HEAD>
<BODY
BGCOLOR=
"#FFFFFF"
LINK=
"#000099"
VLINK=
"#555555"
>
<dtml-var
manage_tabs
>
<P>
You may upload the source for
&dtml-title_and_id;
using the form below.
Choose an existing file from your local computer by pushing the
<I>
Browse
</I>
button. The contents of the file should be a
valid script with an optional
"
##data
"
block at the start.
You may click the following link to
<a
href=
"document_src"
>
view or
download
</a>
the current source.
<FORM
ACTION=
"ZPythonScriptHTML_upload"
METHOD=
"POST"
ENCTYPE=
"multipart/form-data"
>
<TABLE
CELLSPACING=
"2"
>
<TR>
<TH
ALIGN=
"LEFT"
VALIGN=
"TOP"
>
File
</TH>
<TD
ALIGN=
"LEFT"
VALIGN=
"TOP"
>
<INPUT
TYPE=
"file"
NAME=
"file"
SIZE=
"25"
VALUE=
""
>
</TD>
</TR>
<TR>
<TD></TD>
<TD><BR><INPUT
TYPE=
"SUBMIT"
VALUE=
"Change"
></TD>
</TR>
</TABLE>
</FORM>
</BODY>
</HTML>
lib/python/Products/PythonScripts/www/pyscript.gif
0 → 100644
View file @
6429477d
116 Bytes
lib/python/Products/PythonScripts/www/scriptBindings.dtml
0 → 100644
View file @
6429477d
<html>
<head>
<title>
Bindings -
&dtml-title_or_id;
</title>
</head>
<body
bgcolor=
"#ffffff"
link=
"#000099"
vlink=
"#555555"
alink=
"#77003b"
>
<dtml-var
manage_tabs
>
<h2>
Bindings -
&dtml-title_or_id;
</h2>
<form
action=
"ZBindingsHTML_editAction"
method=
"POST"
>
<dtml-with
getBindingAssignments
>
<p><em>
Each of the following items describes a piece of information about
this script's calling environment. If you supply a variable name for
an item, or accept the recommended name, the information will
automatically be provided under that name when the script is called.
</em></p>
<table
cellpadding=
"2"
>
<tr>
<th
align=
"left"
valign=
"top"
>
Container
</th>
<td
align=
"left"
valign=
"top"
nowrap
><input
type=
"text"
name=
"name_container"
value=
"<dtml-var expr="
getAssignedName
('
name_container
',
'')"
html_quote
>
">
<br>
Recommended:
<code>
self
</code>
</td><td
align=
"left"
valign=
"top"
>
This is the
<dtml-with
expr=
"aq_inner.aq_parent"
>
&dtml-meta_type;
"
&dtml.missing.html_quote-title_or_id;
"
</dtml-with>
, in which this
script is located. This doesn't change unless you move the script.
If the script is in a ZClass, the Container is the class instance.
</td>
</tr>
<tr><td>
</td></tr>
<tr>
<th
align=
"left"
valign=
"top"
>
Context
</th>
<td
align=
"left"
valign=
"top"
><input
type=
"text"
name=
"name_context"
value=
"<dtml-var expr="
getAssignedName
('
name_context
',
'')"
html_quote
>
">
<br>
Recommended:
<code>
context
</code>
</td><td
align=
"left"
valign=
"top"
>
This is the object on which the script is being called, also known as the
"acquisition parent" of the script. This
<em>
may
</em>
be the container, but
varies according to the path through which the script is accessed.
</td>
</tr>
<tr><td>
</td></tr>
<tr>
<th
align=
"left"
valign=
"top"
>
Script
</th>
<td
align=
"left"
valign=
"top"
><input
type=
"text"
name=
"name_m_self"
value=
"<dtml-var expr="
getAssignedName
('
name_m_self
',
'')"
html_quote
>
">
<br>
Recommended:
<code>
m_self
</code>
</td><td
align=
"left"
valign=
"top"
>
This is the object
"&dtml-title_or_id;"
itself.
</td>
</tr>
<tr><td>
</td></tr>
<tr>
<th
align=
"left"
valign=
"top"
>
Namespace
</th>
<td
align=
"left"
valign=
"top"
><input
type=
"text"
name=
"name_ns"
value=
"<dtml-var expr="
getAssignedName
('
name_ns
',
'')"
html_quote
>
">
<br>
Rec:
<code>
_
</code>
(an underscore)
</td><td
align=
"left"
valign=
"top"
>
When the script is called from DTML, this is the caller's DTML namespace,
otherwise it is an empty namespace.
</td>
</tr>
<tr><td>
</td></tr>
<tr>
<th
align=
"left"
valign=
"top"
>
Subpath
</th>
<td
align=
"left"
valign=
"top"
nowrap
><input
type=
"text"
name=
"name_subpath"
value=
"<dtml-var expr="
getAssignedName
('
name_subpath
',
'')"
html_quote
>
">
<br>
Rec:
<code>
traverse_subpath
</code>
</td><td
align=
"left"
valign=
"top"
>
When the script is published directly from a URL, this is the
portion of the URL path after the script's name, split at slash separators
into a list of strings. Otherwise, it is an empty list.
</td>
</tr>
<tr>
<td
align=
"left"
>
<input
name=
"submit"
type=
"submit"
value=
"Change"
>
</td>
</tr>
</table>
</dtml-with>
</form>
</body>
</html>
lib/python/Products/PythonScripts/www/scriptTry.dtml
0 → 100644
View file @
6429477d
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html
lang=
"en"
>
<head>
<title>
Try
<dtml-var
title_or_id
></title>
</head>
<body
bgcolor=
"#ffffff"
link=
"#000099"
vlink=
"#555555"
alink=
"#77003b"
>
<dtml-var
manage_tabs
>
<h2>
Try
<dtml-var
title_or_id
></h2>
<form
action=
"&dtml-URL1;/ZScriptHTML_tryAction"
method=
"POST"
>
<table
cellspacing=
"2"
>
<tr><th>
Variable
</th><th>
Value
</th></tr>
<dtml-in
ZScriptHTML_tryParams
>
<tr>
<td
align=
"left"
valign=
"top"
>
<input
name=
"argvars.name:records"
type=
"text"
value=
"&dtml-sequence-item;"
>
</td>
<td
align=
"left"
valign=
"top"
>
<input
name=
"argvars.value:records"
type=
"text"
>
</td>
</tr>
<dtml-else>
<dtml-raise
type=
"Redirect"
>
&dtml-URL1;
</dtml-raise>
</dtml-in>
</table>
<input
name=
"submit"
type=
"submit"
value=
"Go"
><br>
</form>
</body>
</html>
lib/python/Products/PythonScripts/zbytecodehacks/ChangeLog
0 → 100755
View file @
6429477d
1999-12-11 Evan Simpson <evan@4-am.com>
* Tupleizing and UntupleFunction now handle nested function definitions
* Subdirectories reverted to v0.5 bytecodehacks, since the only change
I've ever made was to accidentally change line endings in them to CRLF
1999-09-09 Evan Simpson <evan@4-am.com>
* Tupleizing a function now omits globals
* New UntupleFunction re-applies globals, with automatic initialization
of variables to None, since there's no way to check if they exist.
It also includes $functions, and checks __builtins__ handling.
* Moved all bytecode manipulation into Munge_window class, which uses
op.execute to maintain information about who did what to the stack.
* Added Munger which re-enables creation of dictionary literals.
* Made all Mungers load frequently used functions from the global dict
into the local instead of storing them in co_consts.
* Simplified GuardedOps and turned off test Guard.
* Wrote lots of docstring.
1999-08-28 Evan Simpson <evan@4-am.com>
* Ripped out Fleshy acquisition-style class and added
CycleHandle in an attempt to improve speed.
* code_editor.py: Added "as_tuple" to Function and EditableCode
to provide (hopefully) pickleable representations. Their __init__s
now accept these tuples.
* Added VSExec.py (the point of all this), which provides facilities
for compiling arbitrary blocks of code with heavy restrictions.
1999-06-11 Michael Hudson <mwh21@cam.ac.uk>
* a monumental amount has changed. I haven't been keeping the
ChangeLog up to date, sorry.
1999-05-16 Michael Hudson <mwh21@cam.ac.uk>
* doc/bch.tex: documented macro and macros.
* macros.py: added basic library of macros.
* setq2.py: does same job as setq.py, but uses the new macro
package.
* macro.py It's a macro packages of sorts. Needs documentation.
1999-05-15 Michael Hudson <mwh21@cam.ac.uk>
* inline.py: Substantially rewritten to use find_function_call,
and to support keyword arguments. No varags yet.
* setq.py Added changes written by Christian Tismer (now converts
globals to locals)
1999-05-13 Michael Hudson <mwh21@cam.ac.uk>
* Release 0.11 - cleaned up production of documentation following
advice from the documentation master, Fred L. Drake.
1999-05-12 Michael Hudson <mwh21@cam.ac.uk>
* Release 0.10.
* doc/ There's documentation (gasp)
1999-05-10 Michael Hudson <mwh21@cam.ac.uk>
* inline.py: Python now has inline functions! Bet you never
expected that.
* It's all changing again! Much polish, some docstrings,
everything rewritten to use code_editor that wasn't already, many
style fixes.
1999-05-06 Michael Hudson <mwh21@cam.ac.uk>
* attr_freeze.py: implement an attribute freezer that works.
* xapply2.py: implement xapply for functions (again!) using the
new code editing framework from code_editor.py.
* code_editor.py: That's more like it!
1999-05-04 Michael Hudson <mwh21@cam.ac.uk>
* attr_freeze.py: implements a (buggy) attempt at freezing
attribute references.
* read_code.py,opbases.py,ops.py,write_ops.py,
common.py,__init__.py: Much stuff added/changed. It not pretty or
internally consistent yet. I might bash on it some more some
time. I'm afraid I don't feel like explaining myself properly yet
either.
1999-05-02 Michael Hudson <mwh21@cam.ac.uk>
* README,ChangeLog: Added.
* xapply.py: Added, following prompting by Christian Tismer.
* closure.py: Made improvements suggested by Tim Peters.
lib/python/Products/PythonScripts/zbytecodehacks/Makefile
0 → 100755
View file @
6429477d
SUBDIRS
=
tests code_gen doc
clean
:
clean-local clean-recursive
release
:
version src-release doc-release
clean-local
:
$(RM)
*
.pyc
*
~
*
.pyo
clean-recursive
:
for
i
in
$(SUBDIRS)
;
do
\
(
cd
$$
i
&&
make clean
)
;
\
done
src-release
:
clean
cd
..
&&
./mkdist.sh
doc-release
:
clean
cd
doc
&&
make release
lib/python/Products/PythonScripts/zbytecodehacks/README
0 → 100755
View file @
6429477d
Welcome to the bytecodehacks!
There's docmentation in doc/; To build it you need an unpacked python
source distribution somewhere, and for html output you also need
latex2html.
Build docs like this:
$(path to Python source)/Doc/tools/mkhowto --$(format) (--a4) bch.tex
You can get built html docs at
ftp://starship.python.net/pub/crew/mwh/bytecodehacks-doc-$(VERSION).tar.gz.
The bytecodehacks rewrite the bytecode of functions to do unlikely
things in Python.
The package (and that's how it's distributed) splits into two parts -
the byte code editing routines and the "bytecodehacks" that are
usuable without a degree in python arcanery, although one might help
understand some of the consequences.
Some highlights:
bytecodehacks.closure - bind global references to constants
bytecodehacks.xapply - a sort-of lazy apply
bytecodehacks.setq - this one should interest people!
bytecodehacks.inline - Python gets inline functions
bytecodehacks.macro - Python gets semantic (hygenic) macros!
Please note that these modules are not really bullet-proof, more a
proof-of-concept than anything else.
The are also public domain; do what you like with them. If you find
bugs, or more imaginative uses for these techniques, I'd surely like
to know!
Thanks for taking an interest.
lib/python/Products/PythonScripts/zbytecodehacks/TODO
0 → 100755
View file @
6429477d
polish attr_freeze.
lib/python/Products/PythonScripts/zbytecodehacks/VSExec.py
0 → 100755
View file @
6429477d
'''Safe execution of arbitrary code through bytecode munging
CodeBlock is a base class for bytecode munging of code strings. Derived
classes should override 'forbid' and 'Mungers'. The class constructor
takes a function name, a parameter string, and a function body string. It
combines the name, parameters, and body into a function (indented one
space), compiles it, and then examines its bytecode.
Any bytecode whose opcode is a key in 'forbid' with a true value may not
appear in the compiled code.
Each object in 'Mungers' is called with the code window object (at start)
and the variable name information for the function. Mungers can use this
opportunity to examine the code and variables, and perform setup operations.
The value returned from the call is discarded if false, otherwise it is
assumed to be a collection of bytecode-specific functions.
The code window object is passed over the bytecodes, maintaining a stack
of "responsible" opcodes. At any given position, the size of the stack
should be the same as the size of the run-time stack would be when that
part of the code is executing, and the top of the stack would have been
put there by the "responsible" opcode.
At each position, the mungers are examined to see if they have a function
corresponding to the current opcode. If so, the function is called with
the code window object. The function can then use the code window object to
examine or change the bytecode.
Once all processing is done, and if there have not been any errors, the
compiled, edited function is converted into a pickleable tuple, which is
stored as attribute 't' of the resulting instance. In order for this to
work, mungers must not place unpickleable objects into the list of constants.
In order for unpickling to be robust, they should not place any function
objects there either. If a function must be provided for use in the
bytecode, it should be loaded from the global dictionary, preferably with an
'illegal' name.
'''
import
sys
from
string
import
replace
,
join
from
types
import
FunctionType
import
ops
,
code_editor
,
new
from
closure
import
bind
class
Warning
(
Exception
):
pass
class
ForbiddenOp
(
Exception
):
pass
general_special_globals
=
{}
class
Munge_window
:
def
__init__
(
self
,
code
,
use_stack
):
self
.
code
=
code
self
.
opn
=
-
1
self
.
use_stack
=
use_stack
if
use_stack
:
self
.
stack
=
[]
self
.
last_empty_stack
=
None
def
insert_code
(
self
,
rcode
,
at
=
None
):
opn
=
self
.
opn
# rcode is passed as a (callables, args) pair
rcode
=
map
(
apply
,
rcode
[
0
],
rcode
[
1
])
if
at
is
None
:
at
=
opn
self
.
code
[
at
:
at
]
=
rcode
self
.
opn
=
opn
+
len
(
rcode
)
return
rcode
def
set_code
(
self
,
rct
=
1
,
rcode
=
()):
'Replace "rct" bytecodes at current position with "rcode"'
opn
=
self
.
opn
# rcode is passed as a (callables, args) pair
if
rcode
:
rcode
=
map
(
apply
,
rcode
[
0
],
rcode
[
1
])
self
.
code
[
opn
:
opn
+
rct
]
=
rcode
if
self
.
use_stack
:
stack
=
self
.
stack
for
op
in
rcode
:
try
:
op
.
execute
(
stack
)
except
:
del
stack
[:]
if
not
stack
:
self
.
last_empty_stack
=
op
self
.
opn
=
opn
+
len
(
rcode
)
-
1
def
advance
(
self
):
self
.
opn
=
opn
=
self
.
opn
+
1
code
=
self
.
code
if
opn
<
len
(
code
):
self
.
op
=
code
.
opcodes
[
opn
]
self
.
opname
=
self
.
op
.
__class__
.
__name__
return
1
elif
opn
==
len
(
code
):
# Hack!
self
.
op
=
None
self
.
opname
=
'finalize'
return
1
def
do_op
(
self
):
if
self
.
use_stack
and
self
.
op
:
op
=
self
.
op
stack
=
self
.
stack
try
:
op
.
execute
(
stack
)
except
:
del
stack
[:]
if
not
stack
:
self
.
last_empty_stack
=
op
def
after_code_for
(
self
,
stack_idx
):
stack
=
self
.
stack
if
stack_idx
<
0
and
len
(
stack
)
+
stack_idx
<
0
:
whichop
=
self
.
last_empty_stack
if
whichop
is
None
:
return
0
else
:
whichop
=
stack
[
stack_idx
]
return
self
.
code
.
index
(
whichop
)
+
1
def
assert_stack_size
(
self
,
size
,
ctxt
):
if
self
.
use_stack
and
len
(
self
.
stack
)
!=
size
:
raise
Warning
,
(
'PythonMethod Bug: %s objects were on the stack '
'%s when only %s should be.'
%
(
len
(
self
.
stack
),
ctxt
,
size
))
def
clear_stack
(
self
):
if
self
.
use_stack
:
del
self
.
stack
[:]
self
.
last_empty_stack
=
self
.
op
class
CodeBlock
:
'''Compile a string containing Python code, with restrictions'''
forbid
=
{}
Mungers
=
()
globals
=
{
'__builtins__'
:
None
}
forbidden
=
"Forbidden operation %s at line %d"
def
__init__
(
self
,
src
,
name
=
'<function>'
,
filename
=
'<string>'
):
self
.
f
=
None
defns
=
{
'__builtins__'
:
None
}
self
.
warnings
,
self
.
errors
=
[],
[]
try
:
exec
src
in
defns
except
SyntaxError
:
import
traceback
self
.
errors
=
traceback
.
format_exception_only
(
SyntaxError
,
sys
.
exc_info
()[
1
])
return
for
v
in
defns
.
values
():
if
type
(
v
)
is
FunctionType
:
block
=
v
break
else
:
raise
SyntaxError
,
'string did not define a function'
# Crack open the resulting function and munge it.
f
=
code_editor
.
Function
(
block
)
f
.
func_name
=
name
f
.
func_globals
=
self
.
globals
f
.
func_code
.
set_filename
(
filename
)
self
.
munge_data
=
{}
self
.
munge
(
f
.
func_code
)
if
not
self
.
errors
:
self
.
t
=
f
.
as_tuple
()
def
munge
(
self
,
fc
,
depth
=
0
):
# Recurse into nested functions first
for
subcode
in
fc
.
subcodes
:
self
.
munge
(
subcode
,
depth
+
1
)
# Make the current recursion depth accessible
self
.
depth
=
depth
code
=
fc
.
co_code
warnings
,
errors
=
self
.
warnings
,
self
.
errors
# Initialize the Munge objects
mungers
=
[]
window
=
Munge_window
(
code
,
1
)
margs
=
(
self
,
window
,
fc
)
for
M
in
self
.
Mungers
:
try
:
mungers
.
append
(
apply
(
M
,
margs
))
except
Exception
,
e
:
errors
.
append
(
e
.
__class__
.
__name__
+
', '
+
str
(
e
))
# Try to collect all initialization errors before failing
if
errors
:
return
# Mungers which only perform an initial pass should return false
mungers
=
filter
(
None
,
mungers
)
line
=
0
;
forbid
=
self
.
forbid
while
window
.
advance
():
op
,
opname
=
window
.
op
,
window
.
opname
if
isinstance
(
op
,
ops
.
SET_LINENO
):
line
=
op
.
arg
window
.
do_op
()
elif
op
and
forbid
.
get
(
op
.
op
,
0
):
errors
.
append
(
self
.
forbidden
%
(
opname
,
line
))
window
.
do_op
()
#???
else
:
for
m
in
mungers
:
handler
=
getattr
(
m
,
opname
,
None
)
if
handler
:
try
:
# Return true to prevent further munging
handled
=
handler
(
window
)
except
ForbiddenOp
:
errors
.
append
(
self
.
forbidden
%
(
opname
,
line
))
except
Exception
,
e
:
raise
errors
.
append
(
e
.
__class__
.
__name__
+
', '
+
str
(
e
))
else
:
if
not
handled
:
continue
break
else
:
window
.
do_op
()
def
__call__
(
self
,
*
args
,
**
kargs
):
F
=
code_editor
.
Function
(
self
.
t
)
F
.
func_globals
=
self
.
globals
self
.
__call__
=
f
=
F
.
make_function
()
return
apply
(
f
,
args
,
kargs
)
def
_print_handler
(
printlist
,
*
txt
):
add
=
printlist
.
append
if
len
(
txt
):
if
printlist
and
printlist
[
-
1
:]
!=
[
'
\
n
'
]:
add
(
' '
)
add
(
str
(
txt
[
0
]))
else
:
add
(
'
\
n
'
)
def
_join_printed
(
printlist
):
return
join
(
printlist
,
''
)
_join_printed
=
bind
(
_join_printed
,
join
=
join
,
map
=
map
,
str
=
str
)
general_special_globals
[
'$print_handler'
]
=
_print_handler
general_special_globals
[
'$join_printed'
]
=
_join_printed
general_special_globals
[
'$printed'
]
=
None
class
Printing
:
'''Intercept print statements
Print statements are either converted to no-ops, or replaced with
calls to a handler. The default handler _print_handler appends the
intended output to a list. 'printed' is made into a reserved name
which can only be used to read the result of _join_printed.
_print_handler and _join_printed should be provided in the global
dictionary as $print_handler and $join_printed'''
lfnames
=
((
'$printed'
,),
(
'$print_handler'
,),
(
'$join_printed'
,))
print_prep
=
(
(
ops
.
LOAD_FAST
,
ops
.
LOAD_FAST
),
(
lfnames
[
1
],
lfnames
[
0
])
)
get_printed
=
(
(
ops
.
LOAD_FAST
,
ops
.
LOAD_FAST
,
ops
.
CALL_FUNCTION
),
(
lfnames
[
2
],
lfnames
[
0
],
(
1
,))
)
init_printed
=
(
(
ops
.
BUILD_LIST
,
ops
.
STORE_GLOBAL
),
((
0
,),
lfnames
[
0
])
)
make_local
=
(
ops
.
LOAD_GLOBAL
,
ops
.
STORE_FAST
)
call_print1
=
(
(
ops
.
CALL_FUNCTION
,
ops
.
POP_TOP
),
((
1
,),
())
)
call_print2
=
(
(
ops
.
CALL_FUNCTION
,
ops
.
POP_TOP
),
((
2
,),
())
)
def
__init__
(
self
,
cb
,
w
,
fc
):
if
'printed'
in
fc
.
co_varnames
:
raise
SyntaxError
,
'"printed" is a reserved word.'
self
.
warnings
,
self
.
depth
=
cb
.
warnings
,
cb
.
depth
self
.
md
=
cb
.
munge_data
[
'Printing'
]
=
cb
.
munge_data
.
get
(
'Printing'
,
{})
self
.
names_used
=
names_used
=
{}
names
=
fc
.
co_names
if
'printed'
in
names
:
names_used
[
0
]
=
names
.
index
(
'printed'
)
names_used
[
2
]
=
1
else
:
self
.
LOAD_GLOBAL
=
None
def
finalize
(
self
,
w
):
names_used
=
self
.
names_used
if
names_used
:
# Load special names used by the function (and $printed always)
ln
=
self
.
lfnames
names_used
[
0
]
=
1
for
i
in
names_used
.
keys
():
w
.
insert_code
(
(
self
.
make_local
,
(
ln
[
i
],
ln
[
i
])),
0
)
# Inform higher-level mungers of name usage
self
.
md
.
update
(
names_used
)
if
self
.
md
and
self
.
depth
==
0
:
# Initialize the $printed variable in the base function
w
.
insert_code
(
self
.
init_printed
,
0
)
if
not
self
.
md
.
has_key
(
2
):
self
.
warnings
.
append
(
"Prints, but never reads 'printed' variable."
)
def
PRINT_ITEM
(
self
,
w
):
# Load the printing function before the code for the operand.
w
.
insert_code
(
self
.
print_prep
,
w
.
after_code_for
(
-
2
))
w
.
assert_stack_size
(
1
,
"at a 'print' statement"
)
# Instead of printing, call our function and discard the result.
w
.
set_code
(
1
,
self
.
call_print2
)
self
.
names_used
[
1
]
=
1
return
1
def
PRINT_NEWLINE
(
self
,
w
):
w
.
assert_stack_size
(
0
,
"at a 'print' statement"
)
w
.
insert_code
(
self
.
print_prep
)
w
.
set_code
(
1
,
self
.
call_print1
)
self
.
names_used
[
1
]
=
1
return
1
def
LOAD_GLOBAL
(
self
,
w
):
if
w
.
op
.
arg
==
self
.
names_used
[
0
]:
# Construct the print result instead of getting non-existent var.
w
.
set_code
(
1
,
self
.
get_printed
)
return
1
general_special_globals
[
'$loop_watcher'
]
=
lambda
:
None
class
LoopLimits
:
'''Try to prevent "excessive" iteration and recursion
Loop ends, 'continue' statements, and function entry points all
call a hook function, which can keep track of iteration and call
depth, and raise an exception to terminate processing.
The hook function should be provided in the global
dictionary as $loop_watcher'''
lwname
=
(
'$loop_watcher'
,)
notify_watcher
=
(
(
ops
.
LOAD_FAST
,
ops
.
CALL_FUNCTION
,
ops
.
POP_TOP
),
(
lwname
,
(
0
,),
())
)
make_local
=
(
ops
.
LOAD_GLOBAL
,
ops
.
STORE_FAST
)
def
__init__
(
self
,
cb
,
w
,
fc
):
pass
def
finalize
(
self
,
w
):
# Localize the watcher, and call it.
w
.
insert_code
(
self
.
notify_watcher
,
0
)
w
.
insert_code
(
(
self
.
make_local
,
(
self
.
lwname
,
self
.
lwname
)),
0
)
def
JUMP_ABSOLUTE
(
self
,
w
):
# Call the watcher before looping
w
.
insert_code
(
self
.
notify_watcher
)
return
1
def
PublicNames
(
cb
,
w
,
fc
):
'''Restrict access to all but public names
Forbid use of any multi-character name starting with _
'''
protected
=
[]
for
name
in
fc
.
co_names
:
if
name
[:
1
]
==
'_'
and
len
(
name
)
>
1
:
protected
.
append
(
name
)
if
protected
:
raise
SyntaxError
,
(
'Names starting with "_" are not allowed (%s).'
%
join
(
protected
,
', '
))
class
AllowMapBuild
:
'''Allow literal mappings to be constructed unmunged
Optimize construction of literal dictionaries, which requires
STORE_SUBSCR, by checking the stack.'''
def
__init__
(
self
,
cb
,
w
,
fc
):
pass
def
STORE_SUBSCR
(
self
,
w
):
if
isinstance
(
w
.
stack
[
-
2
],
ops
.
BUILD_MAP
):
w
.
do_op
()
return
1
def
_get_call
(
w
):
load_guard
=
((
ops
.
LOAD_FAST
,
ops
.
LOAD_ATTR
),
((
'$guard'
,),
(
guard
,)))
# Load the binary guard function before its parameters are computed.
iops
=
w
.
insert_code
(
load_guard
,
w
.
after_code_for
(
-
3
))
# Fix the execution stack to refer to the loaded function.
if
w
.
use_stack
:
w
.
stack
[
-
2
:
-
2
]
=
iops
[
1
:]
# Call guard function instead of performing binary op
w
.
set_code
(
1
,
cf2
)
return
1
def
_SLICE
(
w
):
load_guard
=
((
ops
.
LOAD_FAST
,
ops
.
LOAD_ATTR
,
ops
.
ROT_TWO
),
((
'$guard'
,),
(
'getslice'
,),
()))
# Load the Slice guard and switch it with the argument.
w
.
insert_code
(
load_guard
,
w
.
opn
+
1
)
# Call the slice guard after performing the slice.
w
.
insert_code
(
cf1
,
w
.
opn
+
4
)
return
1
# Code for calling a function with 1 or 2 parameters, respectively
cf1
=
((
ops
.
CALL_FUNCTION
,),
((
1
,),))
cf2
=
((
ops
.
CALL_FUNCTION
,),
((
2
,),))
class
_GuardedOps
:
def
__call__
(
self
,
cb
,
w
,
fc
):
g
=
self
.
guard_name
localize_guard
=
(
(
ops
.
LOAD_GLOBAL
,
ops
.
STORE_FAST
),
((
g
,),(
g
,))
)
# Insert setup code; no need to fix stack
w
.
insert_code
(
localize_guard
,
0
)
return
self
def
GuardedBinaryOps
(
guards
):
'''Allow operations to be Guarded, by replacing them with guard calls.
Construct a munging object which will replace specific opcodes with
calls to methods of a guard object. The guard object must appear in
the global dictionary as $guard.'''
gops
=
_GuardedOps
()
gops
.
guard_name
=
'$guard'
opmap
=
(
(
'mul'
,
'BINARY_MULTIPLY'
)
,(
'div'
,
'BINARY_DIVIDE'
)
,(
'power'
,
'BINARY_POWER'
)
)
for
guard
,
defname
in
opmap
:
if
hasattr
(
guards
,
guard
):
setattr
(
gops
,
defname
,
bind
(
_get_call
,
guard
=
guard
,
cf2
=
cf2
))
if
hasattr
(
guards
,
'getslice'
):
gops
.
SLICE_3
=
gops
.
SLICE_2
=
gops
.
SLICE_1
=
gops
.
SLICE_0
=
bind
(
_SLICE
,
cf1
=
cf1
)
return
gops
def
_wrap
(
w
):
load_guard
=
((
ops
.
LOAD_FAST
,),
((
guard
,),))
# Load the guard function before the guarded object, call after.
w
.
insert_code
(
load_guard
,
w
.
after_code_for
(
spos
-
1
))
if
spos
==
0
:
w
.
set_code
(
0
,
cf1
)
else
:
iops
=
w
.
insert_code
(
cf1
,
w
.
after_code_for
(
spos
))
# Fix the execution stack.
if
w
.
use_stack
:
w
.
stack
[
spos
]
=
iops
[
0
]
def
_WriteGuardWrapper
():
def
model_handler
(
self
,
*
args
):
try
:
f
=
getattr
(
self
.
__dict__
[
'_ob'
],
secattr
)
except
AttributeError
:
raise
TypeError
,
error_msg
apply
(
f
,
args
)
d
=
{}
for
name
,
error_msg
in
(
(
'setitem'
,
'object does not support item assignment'
),
(
'delitem'
,
'object does not support item deletion'
),
(
'setattr'
,
'attribute-less object (assign or del)'
),
(
'delattr'
,
'attribute-less object (assign or del)'
),
(
'setslice'
,
'object does not support slice assignment'
),
(
'delslice'
,
'object does not support slice deletion'
),
):
fname
=
'__%s__'
%
name
d
[
fname
]
=
bind
(
model_handler
,
fname
,
secattr
=
'__guarded_%s__'
%
name
,
error_msg
=
error_msg
)
return
new
.
classobj
(
'Wrapper'
,
(),
d
)
def
_WriteGuard
(
ob
):
if
type
(
ob
)
in
safetypes
or
getattr
(
ob
,
'_guarded_writes'
,
None
):
return
ob
w
=
Wrapper
()
w
.
__dict__
[
'_ob'
]
=
ob
return
w
WriteGuard
=
bind
(
_WriteGuard
,
safetypes
=
(
type
([]),
type
({})),
Wrapper
=
_WriteGuardWrapper
())
def
RedirectWrites
():
'''Redirect STORE_* and DELETE_* on objects to methods
Construct a munging object which will wrap all objects which are the
target of a STORE or DELETE op by passing them to a guard function.
The guard function must appear in the global dictionary as $write_guard.'''
gops
=
_GuardedOps
()
gops
.
guard_name
=
guard
=
'$write_guard'
opmap
=
(
(
'STORE_SUBSCR'
,
-
2
)
,(
'DELETE_SUBSCR'
,
-
2
)
,(
'STORE_ATTR'
,
-
1
)
,(
'DELETE_ATTR'
,
-
1
)
,(
'STORE_SLICE_0'
,
-
1
)
,(
'STORE_SLICE_1'
,
-
2
)
,(
'STORE_SLICE_2'
,
-
2
)
,(
'STORE_SLICE_3'
,
-
3
)
,(
'DELETE_SLICE_0'
,
-
1
)
,(
'DELETE_SLICE_1'
,
-
2
)
,(
'DELETE_SLICE_2'
,
-
2
)
,(
'DELETE_SLICE_3'
,
-
3
)
)
for
defname
,
spos
in
opmap
:
setattr
(
gops
,
defname
,
bind
(
_wrap
,
spos
=
spos
,
cf2
=
cf2
,
guard
=
guard
))
return
gops
def
_ReadGuard
(
ob
):
if
type
(
ob
)
in
safetypes
or
hasattr
(
ob
,
'_guarded_reads'
):
return
ob
w
=
Wrapper
()
w
.
__dict__
[
'_ob'
]
=
ob
return
w
ReadGuard
=
bind
(
_ReadGuard
,
safetypes
=
(
type
(
''
),))
def
RedirectReads
():
'''Redirect LOAD_* on objects to methods
Construct a munging object which will wrap all objects which are the
target of a LOAD op by passing them to a guard function.
The guard function must appear in the global dictionary as $read_guard.'''
gops
=
_GuardedOps
()
gops
.
guard_name
=
guard
=
'$read_guard'
opmap
=
(
(
'BINARY_SUBSCR'
,
-
2
)
,(
'LOAD_ATTR'
,
-
1
)
,(
'SLICE_0'
,
-
1
)
,(
'SLICE_1'
,
-
2
)
,(
'SLICE_2'
,
-
2
)
,(
'SLICE_3'
,
-
3
)
)
for
defname
,
spos
in
opmap
:
setattr
(
gops
,
defname
,
bind
(
_wrap
,
spos
=
spos
,
cf2
=
cf2
,
guard
=
guard
))
return
gops
class
SafeBlock
(
CodeBlock
):
forbid
=
{
ops
.
STORE_NAME
.
op
:
1
,
ops
.
DELETE_NAME
.
op
:
1
}
for
opclass
in
ops
.
_bytecodes
.
values
():
if
forbid
.
get
(
opclass
.
op
,
1
):
opname
=
opclass
.
__name__
if
opname
[:
5
]
==
'EXEC_'
:
forbid
[
opclass
.
op
]
=
1
Mungers
=
[
Printing
,
PublicNames
,
AllowMapBuild
]
def
UntupleFunction
(
t
,
special_globals
,
**
globals
):
import
new
globals
.
update
(
general_special_globals
)
globals
.
update
(
special_globals
)
globals
[
'global_exists'
]
=
defined
=
globals
.
has_key
if
not
defined
(
'__builtins__'
):
globals
[
'__builtins__'
]
=
{}
t
=
list
(
t
)
# Handle nested functions and lambdas
t_code
=
t
[
2
]
if
len
(
t_code
)
==
13
:
sub_codes
=
[
t_code
]
funstack
=
[
sub_codes
]
while
funstack
:
if
len
(
t_code
)
==
13
:
# This has nested code objects, so make it mutable
sub_codes
[
0
]
=
t_parent
=
t_code
=
list
(
t_code
)
# Put the list of nested codes on the stack for processing
sub_codes
=
list
(
t_code
.
pop
())
funstack
.
append
(
sub_codes
)
else
:
# This code tuple is fully processed, so untuple it
func_code
=
apply
(
new
.
code
,
tuple
(
t_code
))
# Find the first placeholder () in the parent's constants
t_consts
=
list
(
t_parent
[
5
])
# Replace the placeholder with the code object
t_consts
[
t_consts
.
index
(())]
=
func_code
t_parent
[
5
]
=
tuple
(
t_consts
)
# Clear it from the stack
del
sub_codes
[
0
]
# Get the next code tuple to process
if
not
sub_codes
:
# Back up one level
funstack
.
pop
()
sub_codes
=
funstack
[
-
1
]
if
len
(
funstack
)
>
1
:
t_parent
=
funstack
[
-
2
][
0
]
else
:
funstack
=
None
t_code
=
sub_codes
[
0
]
f
=
new
.
function
(
apply
(
new
.
code
,
tuple
(
t_code
)),
globals
,
t
[
0
])
f
.
func_defaults
=
t
[
3
]
and
tuple
(
t
[
3
])
f
.
func_doc
=
t
[
1
]
return
f
def
test
(
p
,
c
):
sb
=
SafeBlock
(
'f'
,
p
,
c
)
print
sb
.
errors
,
sb
.
warnings
f
=
code_editor
.
Function
(
sb
.
t
)
for
c
in
f
.
func_code
.
co_code
:
print
c
for
subcode
in
f
.
func_code
.
subcodes
:
for
c
in
subcode
.
co_code
:
print
' '
,
c
return
sb
if
__name__
==
'__main__'
:
sb
=
test
(
'x'
,
'''
\
print x
def plus1(x):
print x+1
plus1(x)
return printed'''
)
f
=
UntupleFunction
(
sb
.
t
,
{})
#from dis import dis
#dis(f)
print
f
(
2
),
print
f
(
3
),
lib/python/Products/PythonScripts/zbytecodehacks/__init__.py
0 → 100755
View file @
6429477d
__all__
=
[
'closure'
,
'xapply'
,
'common'
,
'inline'
,
'code_editor'
,
'opbases'
,
'ops'
,
'attr_freeze'
,
'code_gen'
]
lib/python/Products/PythonScripts/zbytecodehacks/attr_freeze.py
0 → 100755
View file @
6429477d
from
code_editor
import
Function
from
ops
import
LOAD_GLOBAL
,
LOAD_ATTR
,
LOAD_CONST
def
freeze_one_attr
(
cs
,
code
,
attr
,
value
):
looking_for
=
0
is_global
=
1
inserted
=
0
i
=
0
while
i
<
len
(
cs
):
op
=
cs
[
i
]
if
is_global
:
if
op
.
__class__
is
LOAD_GLOBAL
:
if
code
.
co_names
[
op
.
arg
]
==
attr
[
looking_for
]:
looking_for
=
looking_for
+
1
is_global
=
0
else
:
if
op
.
__class__
is
LOAD_ATTR
\
and
code
.
co_names
[
op
.
arg
]
==
attr
[
looking_for
]:
looking_for
=
looking_for
+
1
if
looking_for
==
len
(
attr
):
inserted
=
1
newop
=
LOAD_CONST
(
len
(
code
.
co_consts
))
cs
[
i
-
len
(
attr
)
+
1
:
i
+
1
]
=
[
newop
]
i
=
i
-
len
(
attr
)
looking_for
=
0
is_global
=
1
else
:
looking_for
=
0
is_global
=
1
i
=
i
+
1
if
inserted
:
code
.
co_consts
.
append
(
value
)
return
cs
class
Ref
:
def
__init__
(
self
,
name
=
()):
self
.
name
=
name
def
__getattr__
(
self
,
attr
):
return
Ref
(
self
.
name
+
(
attr
,))
def
__call__
(
self
):
return
self
.
name
def
__repr__
(
self
):
return
`self.name`
def
freeze_attrs
(
func
,
*
vars
):
func
=
Function
(
func
)
code
=
func
.
func_code
cs
=
code
.
co_code
if
len
(
vars
)
%
2
<>
0
:
raise
TypeError
,
"wrong number of arguments"
for
i
in
range
(
0
,
len
(
vars
),
2
):
freeze_one_attr
(
cs
,
code
,
vars
[
i
](),
vars
[
i
+
1
])
return
func
.
make_function
()
lib/python/Products/PythonScripts/zbytecodehacks/closure.py
0 → 100755
View file @
6429477d
"""
\
closure
implements a form of closures by abusing the co_consts field of a code
object.
exports: bind, bind_locals, bind_now
and contains two examples: make_adder, make_balance
"""
from
code_editor
import
Function
from
ops
import
*
def
scan_for_STORE
(
func
,
name
):
for
i
in
func
.
func_code
.
co_code
:
if
i
.
__class__
in
[
STORE_FAST
,
STORE_NAME
,
STORE_GLOBAL
]
\
and
i
.
name
==
name
:
return
1
return
0
def
bind
(
function
,
newname
=
None
,
**
vars
):
"""
\
bind(function[,newname],var1=value1,var2=value2,...) -> function
returns a new function (optionally renamed) where every reference to
one of var1, var2, etc is replaced by a reference to the respective
valueN."""
func
=
Function
(
function
)
code
=
func
.
func_code
cs
=
func
.
func_code
.
co_code
name2index
=
{}
mutated
=
{}
for
name
in
vars
.
keys
():
mutated
[
name
]
=
scan_for_STORE
(
func
,
name
)
if
0
in
code
.
co_consts
:
zeroIndex
=
code
.
co_consts
.
index
(
0
)
else
:
zeroIndex
=
len
(
code
.
co_consts
)
code
.
co_consts
.
append
(
0
)
i
=
0
while
i
<
len
(
cs
):
op
=
cs
[
i
]
i
=
i
+
1
# should LOAD_NAME be here??? tricky, I'd say
if
op
.
__class__
in
[
LOAD_GLOBAL
,
LOAD_NAME
,
LOAD_FAST
]:
if
not
vars
.
has_key
(
op
.
name
):
continue
if
mutated
[
name
]:
if
not
name2index
.
has_key
(
op
.
name
):
name2index
[
op
.
name
]
=
len
(
code
.
co_consts
)
code
.
co_consts
.
append
([
vars
[
op
.
name
]])
cs
[
i
-
1
:
i
]
=
[
LOAD_CONST
(
name2index
[
op
.
name
]),
LOAD_CONST
(
zeroIndex
),
BINARY_SUBSCR
()]
i
=
i
+
2
else
:
if
not
name2index
.
has_key
(
op
.
name
):
name2index
[
op
.
name
]
=
len
(
code
.
co_consts
)
code
.
co_consts
.
append
(
vars
[
op
.
name
])
cs
[
i
-
1
]
=
LOAD_CONST
(
name2index
[
op
.
name
])
elif
op
.
__class__
in
[
STORE_FAST
,
STORE_NAME
,
STORE_GLOBAL
]:
if
not
vars
.
has_key
(
op
.
name
):
continue
if
not
mutated
[
name
]:
continue
# shouldn't be reached
cs
[
i
-
1
:
i
]
=
[
LOAD_CONST
(
name2index
[
op
.
name
]),
LOAD_CONST
(
zeroIndex
),
STORE_SUBSCR
()]
i
=
i
+
2
if
newname
is
not
None
:
func
.
func_name
=
newname
return
func
.
make_function
()
bind
=
Function
(
bind
)
bind
.
func_code
.
co_varnames
[
0
]
=
'$function'
bind
.
func_code
.
co_varnames
[
1
]
=
'$newname'
bind
=
bind
.
make_function
()
def
bind_locals
(
func
):
"""bind_locals(func) -> function
returns a new function where every global variable reference in func
is replaced, if possible, by a reference to a local variable in the
callers context."""
try
:
raise
""
except
:
import
sys
frame
=
sys
.
exc_traceback
.
tb_frame
.
f_back
name
=
func
.
func_name
+
'+'
l
=
apply
(
bind
,(
func
,
name
),
frame
.
f_locals
)
frame
=
None
return
l
def
bind_now
(
func
):
"""bind_now(func) -> function
returns a new function where every global variable reference in func
is replaced, if possible, by a reference to a variable in the callers
context."""
try
:
raise
""
except
:
import
sys
frame
=
sys
.
exc_traceback
.
tb_frame
.
f_back
l
=
apply
(
bind
,(
func
,),
frame
.
f_locals
)
g
=
apply
(
bind
,(
l
,),
frame
.
f_globals
)
frame
=
None
return
g
## examples
def
make_adder
(
n
):
"""make_adder(n) -> function
return a monadic function that adds n to its argument."""
def
adder
(
x
):
return
x
+
n
return
bind_locals
(
adder
)
def
make_balance
(
initial_amount
):
"""make_balance(initial_amount) -> function
demonstrates an object with state, sicp style."""
def
withdraw
(
amount
):
if
current
[
0
]
<
amount
:
raise
"debt!"
else
:
current
[
0
]
=
current
[
0
]
-
amount
return
current
[
0
]
return
bind
(
withdraw
,
current
=
[
initial_amount
])
lib/python/Products/PythonScripts/zbytecodehacks/code_editor.py
0 → 100755
View file @
6429477d
# the third attempt; maybe it'll work sometime.
# interface I want:
# mc=MutableCode(<code object>)
# behaves like list of opcodes, eg
# len(mc) => number of bytecodes in code
# mc[i] returns some representation of the ith opcode
# mc.assemble() => codestring, or maybe code object.
import
types
,
StringIO
,
struct
,
new
import
ops
from
cyclehandle
import
CycleHandle
class
CodeString
(
CycleHandle
):
def
__init__
(
self
,
cs
=
None
,
bytecodes
=
None
):
self
.
_set_workers
(
CodeStringWorker
(
cs
,
bytecodes
))
class
CodeStringWorker
:
def
__init__
(
self
,
cs
,
bytecodes
):
self
.
labels
=
[]
self
.
byte2op
=
{}
self
.
opcodes
=
[]
if
bytecodes
is
None
:
bytecodes
=
ops
.
_bytecodes
if
type
(
cs
)
is
type
(
""
):
self
.
disassemble_no_code
(
cs
,
bytecodes
)
else
:
self
.
disassemble
(
cs
,
bytecodes
)
def
disassemble
(
self
,
code
,
bytecodes
):
self
.
labels
=
[]
self
.
byte2op
=
{}
self
.
opcodes
=
[]
self
.
code
=
code
cs
=
StringIO
.
StringIO
(
code
.
co_code
)
i
,
op
,
n
=
0
,
0
,
len
(
code
.
co_code
)
while
i
<
n
:
self
.
byte2op
[
i
]
=
op
byte
=
cs
.
read
(
1
)
self
.
opcodes
.
append
(
bytecodes
[
byte
](
cs
,
self
))
i
=
cs
.
tell
()
op
=
op
+
1
del
self
.
code
for
label
in
self
.
labels
:
label
.
resolve
(
self
)
def
disassemble_no_code
(
self
,
codestring
,
bytecodes
):
self
.
labels
=
[]
self
.
byte2op
=
{}
self
.
opcodes
=
[]
cs
=
StringIO
.
StringIO
(
codestring
)
i
,
op
,
n
=
0
,
0
,
len
(
codestring
)
while
i
<
n
:
self
.
byte2op
[
i
]
=
op
byte
=
cs
.
read
(
1
)
self
.
opcodes
.
append
(
bytecodes
[
byte
](
cs
,
self
))
i
=
cs
.
tell
()
op
=
op
+
1
for
label
in
self
.
labels
:
label
.
resolve
(
self
)
def
add_label
(
self
,
label
):
self
.
labels
.
append
(
label
)
def
find_labels
(
self
,
index
):
labelled
=
self
.
opcodes
[
index
]
pointees
=
[]
for
l
in
self
.
labels
:
if
l
.
op
==
labelled
:
pointees
.
append
(
l
)
return
pointees
def
__getitem__
(
self
,
index
):
return
self
.
opcodes
[
index
]
def
__setitem__
(
self
,
index
,
value
):
# find labels that point to the removed opcode
pointees
=
self
.
find_labels
(
index
)
if
self
.
opcodes
[
index
].
is_jump
():
self
.
labels
.
remove
(
self
.
opcodes
[
index
].
label
)
self
.
opcodes
[
index
]
=
value
for
l
in
pointees
:
l
.
op
=
value
if
value
.
is_jump
():
self
.
labels
.
append
(
value
.
label
)
def
__delitem__
(
self
,
index
):
# labels that pointed to the deleted item get attached to the
# following insn (unless it's the last insn - in which case I
# don't know what you're playing at, but I'll just point the
# label at what becomes the last insn)
pointees
=
self
.
find_labels
(
index
)
if
index
+
1
==
len
(
self
.
opcodes
):
replacement
=
self
.
opcodes
[
index
]
else
:
replacement
=
self
.
opcodes
[
index
+
1
]
for
l
in
pointees
:
l
.
op
=
replacement
going
=
self
.
opcodes
[
index
]
if
going
.
is_jump
():
self
.
labels
.
remove
(
going
.
label
)
del
self
.
opcodes
[
index
]
def
__getslice__
(
self
,
lo
,
hi
):
return
self
.
opcodes
[
lo
:
hi
]
def
__setslice__
(
self
,
lo
,
hi
,
values
):
# things that point into the block being stomped on get
# attached to the start of the new block (if there are labels
# pointing into the block, rather than at its start, a warning
# is printed, 'cause that's a bit dodgy)
pointees
=
[]
opcodes
=
self
.
opcodes
indices
=
range
(
len
(
opcodes
))[
lo
:
hi
]
for
i
in
indices
:
if
opcodes
[
i
].
is_jump
():
self
.
labels
.
remove
(
opcodes
[
i
].
label
)
p
=
self
.
find_labels
(
i
)
if
p
and
i
<>
lo
:
print
"What're you playing at?"
pointees
.
extend
(
p
)
codes
=
[]
for
value
in
values
:
if
value
.
is_jump
():
self
.
labels
.
append
(
value
.
label
)
codes
.
append
(
value
)
opcodes
[
lo
:
hi
]
=
codes
replacement
=
opcodes
[
min
(
lo
,
len
(
opcodes
)
-
1
)]
for
l
in
pointees
:
l
.
op
=
replacement
def
__delslice__
(
self
,
lo
,
hi
):
self
.
__setslice__
(
lo
,
hi
,
[])
def
__len__
(
self
):
return
len
(
self
.
opcodes
)
def
append
(
self
,
value
):
self
.
opcodes
.
append
(
value
)
if
value
.
is_jump
():
self
.
labels
.
append
(
value
.
label
)
def
insert
(
self
,
index
,
value
):
self
.
opcodes
.
insert
(
index
,
value
)
if
value
.
is_jump
():
self
.
labels
.
append
(
value
.
label
)
def
remove
(
self
,
x
):
del
self
[
self
.
opcodes
.
index
(
x
)]
def
index
(
self
,
x
):
return
self
.
opcodes
.
index
(
x
)
def
assemble
(
self
):
out
=
StringIO
.
StringIO
()
for
i
in
self
:
i
.
byte
=
out
.
tell
()
out
.
write
(
i
.
assemble
(
self
))
for
l
in
self
.
labels
:
l
.
write_refs
(
out
)
out
.
seek
(
0
)
return
out
.
read
()
def
set_code
(
self
,
code
):
self
.
code
=
code
class
EditableCode
(
CycleHandle
):
def
__init__
(
self
,
code
=
None
):
self
.
_set_workers
(
EditableCodeWorker
(
code
))
class
EditableCodeWorker
:
# bits for co_flags
CO_OPTIMIZED
=
0x0001
CO_NEWLOCALS
=
0x0002
CO_VARARGS
=
0x0004
CO_VARKEYWORDS
=
0x0008
AUTO_RATIONALIZE
=
0
def
__init__
(
self
,
code
=
None
):
if
code
is
None
:
self
.
init_defaults
()
elif
type
(
code
)
in
(
type
(()),
type
([])):
self
.
init_tuple
(
code
)
else
:
self
.
init_code
(
code
)
self
.
co_code
.
set_code
(
self
)
def
name_index
(
self
,
name
):
if
name
not
in
self
.
co_names
:
self
.
co_names
.
append
(
name
)
return
self
.
co_names
.
index
(
name
)
def
local_index
(
self
,
name
):
if
name
not
in
self
.
co_varnames
:
self
.
co_varnames
.
append
(
name
)
return
self
.
co_varnames
.
index
(
name
)
def
rationalize
(
self
):
from
rationalize
import
rationalize
rationalize
(
self
)
def
init_defaults
(
self
):
self
.
co_argcount
=
0
self
.
co_stacksize
=
0
# ???
self
.
co_flags
=
0
# ???
self
.
co_consts
=
[]
self
.
co_names
=
[]
self
.
co_varnames
=
[]
self
.
co_filename
=
'<edited code>'
self
.
co_name
=
'no name'
self
.
co_firstlineno
=
0
self
.
co_lnotab
=
''
# ???
self
.
co_code
=
CodeString
()
self
.
subcodes
=
[]
def
init_code
(
self
,
code
):
self
.
co_argcount
=
code
.
co_argcount
self
.
co_stacksize
=
code
.
co_stacksize
self
.
co_flags
=
code
.
co_flags
self
.
co_consts
=
consts
=
list
(
code
.
co_consts
)
self
.
co_names
=
list
(
code
.
co_names
)
self
.
co_varnames
=
list
(
code
.
co_varnames
)
self
.
co_filename
=
code
.
co_filename
self
.
co_name
=
code
.
co_name
self
.
co_firstlineno
=
code
.
co_firstlineno
self
.
co_lnotab
=
code
.
co_lnotab
self
.
co_code
=
CodeString
(
code
)
self
.
subcodes
=
subcodes
=
[]
from
types
import
CodeType
for
i
in
range
(
len
(
consts
)):
if
type
(
consts
[
i
])
==
CodeType
:
subcodes
.
append
(
EditableCode
(
consts
[
i
]))
consts
[
i
]
=
()
def
init_tuple
(
self
,
tup
):
self
.
subcodes
=
[]
if
len
(
tup
)
==
13
:
self
.
subcodes
=
map
(
EditableCode
,
tup
[
-
1
])
tup
=
tup
[:
-
1
]
(
self
.
co_argcount
,
ignored
,
self
.
co_stacksize
,
self
.
co_flags
,
self
.
co_code
,
co_consts
,
co_names
,
co_varnames
,
self
.
co_filename
,
self
.
co_name
,
self
.
co_firstlineno
,
self
.
co_lnotab
)
=
tup
self
.
co_consts
=
list
(
co_consts
)
self
.
co_names
=
list
(
co_names
)
self
.
co_varnames
=
list
(
co_varnames
)
self
.
co_code
=
CodeString
(
self
)
def
make_code
(
self
):
if
self
.
AUTO_RATIONALIZE
:
self
.
rationalize
()
else
:
# hack to deal with un-arg-ed names
for
op
in
self
.
co_code
:
if
(
op
.
has_name
()
or
op
.
has_local
())
and
not
hasattr
(
op
,
"arg"
):
if
op
.
has_name
():
op
.
arg
=
self
.
name_index
(
op
.
name
)
else
:
op
.
arg
=
self
.
local_index
(
op
.
name
)
return
apply
(
new
.
code
,
self
.
as_tuple
()[:
12
])
def
set_function
(
self
,
function
):
self
.
function
=
function
def
set_name
(
self
,
name
):
self
.
co_name
=
name
def
set_filename
(
self
,
filename
):
self
.
co_filename
=
filename
def
as_tuple
(
self
):
# the assembling might change co_names or co_varnames - so
# make sure it's done *before* we start gathering them.
bytecode
=
self
.
co_code
.
assemble
()
subcodes
=
[]
for
subcode
in
self
.
subcodes
:
subcodes
.
append
(
subcode
.
as_tuple
())
return
(
self
.
co_argcount
,
len
(
self
.
co_varnames
),
self
.
co_stacksize
,
self
.
co_flags
,
bytecode
,
tuple
(
self
.
co_consts
),
tuple
(
self
.
co_names
),
tuple
(
self
.
co_varnames
),
self
.
co_filename
,
self
.
co_name
,
self
.
co_firstlineno
,
self
.
co_lnotab
,
tuple
(
subcodes
))
class
Function
(
CycleHandle
):
def
__init__
(
self
,
func
=
None
):
self
.
_set_workers
(
FunctionWorker
(
func
))
class
FunctionWorker
:
def
__init__
(
self
,
func
):
if
func
is
None
:
self
.
init_defaults
()
elif
type
(
func
)
in
(
type
(()),
type
([])):
self
.
init_tuple
(
func
)
else
:
self
.
init_func
(
func
)
self
.
func_code
.
set_function
(
self
)
def
init_defaults
(
self
):
self
.
__name
=
"no name"
self
.
__doc
=
None
self
.
func_code
=
EditableCode
()
self
.
func_defaults
=
[]
self
.
func_globals
=
{}
# ???
def
init_func
(
self
,
func
):
self
.
__name
=
func
.
func_name
self
.
__doc
=
func
.
func_doc
self
.
func_code
=
EditableCode
(
func
.
func_code
)
self
.
func_defaults
=
func
.
func_defaults
self
.
func_globals
=
func
.
func_globals
def
init_tuple
(
self
,
tup
):
(
self
.
__name
,
self
.
__doc
,
func_code
,
self
.
func_defaults
,
self
.
func_globals
)
=
tup
self
.
func_code
=
EditableCode
(
func_code
)
def
__getattr__
(
self
,
attr
):
# for a function 'f.__name__ is f.func_name'
# so lets hack around to support that...
if
attr
in
[
'__name__'
,
'func_name'
]:
return
self
.
__name
if
attr
in
[
'__doc__'
,
'func_doc'
]:
return
self
.
__doc
raise
AttributeError
,
attr
def
__setattr__
(
self
,
attr
,
value
):
if
attr
in
[
'__name__'
,
'func_name'
]:
self
.
__name
=
value
elif
attr
in
[
'__doc__'
,
'func_doc'
]:
self
.
__doc
=
value
else
:
self
.
__dict__
[
attr
]
=
value
def
make_function
(
self
):
self
.
func_code
.
set_name
(
self
.
__name
)
newfunc
=
new
.
function
(
self
.
func_code
.
make_code
(),
self
.
func_globals
,
self
.
__name
)
if
not
self
.
func_defaults
:
defs
=
None
else
:
defs
=
tuple
(
self
.
func_defaults
)
newfunc
.
func_defaults
=
defs
newfunc
.
func_doc
=
self
.
__doc
return
newfunc
def
__call__
(
self
,
*
args
,
**
kw
):
return
apply
(
self
.
make_function
(),
args
,
kw
)
def
set_method
(
self
,
method
):
self
.
method
=
method
def
as_tuple
(
self
):
self
.
func_code
.
set_name
(
self
.
__name
)
if
not
self
.
func_defaults
:
defs
=
None
else
:
defs
=
tuple
(
self
.
func_defaults
)
return
(
self
.
__name
,
self
.
__doc
,
self
.
func_code
.
as_tuple
(),
defs
,
{})
class
InstanceMethod
(
CycleHandle
):
def
__init__
(
self
,
meth
=
None
):
self
.
_set_workers
(
InstanceMethodWorker
(
meth
))
class
InstanceMethodWorker
:
def
__init__
(
self
,
meth
):
if
meth
is
None
:
self
.
init_defaults
()
else
:
self
.
init_meth
(
meth
)
self
.
im_func
.
set_method
(
self
)
def
init_defaults
(
self
):
self
.
im_class
=
None
self
.
im_func
=
Function
()
self
.
im_self
=
None
def
init_meth
(
self
,
meth
):
self
.
im_class
=
meth
.
im_class
self
.
im_func
=
Function
(
meth
.
im_func
)
self
.
im_self
=
meth
.
im_self
def
make_instance_method
(
self
):
return
new
.
instancemethod
(
self
.
im_func
.
make_function
(),
self
.
im_self
,
self
.
im_class
)
class
FunctionOrMethod
:
def
__init__
(
self
,
functionormethod
):
if
type
(
functionormethod
)
is
types
.
FunctionType
:
self
.
is_method
=
0
self
.
function
=
Function
(
functionormethod
)
elif
type
(
functionormethod
)
is
types
.
UnboundMethodType
:
self
.
is_method
=
1
self
.
method
=
InstanceMethod
(
functionormethod
)
self
.
function
=
self
.
method
.
im_func
def
make_function_or_method
(
self
):
if
self
.
is_method
:
return
self
.
method
.
make_instance_method
()
else
:
return
self
.
function
.
make_function
()
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/Makefile
0 → 100644
View file @
6429477d
clean
:
$(RM)
*
~
*
.pyc
*
.pyo
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/__init__.py
0 → 100644
View file @
6429477d
__all__
=
[
'write_ops'
,
'opexecfuncread'
]
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/op_execute_methods
0 → 100644
View file @
6429477d
# -*- python -*-
STOP_CODE
:
pass
POP_TOP
:
stack
.
pop
()
ROT_TWO
:
stack
[
-
2
:]
=
[
stack
[
-
1
],
stack
[
-
2
]]
ROT_THREE
:
stack
[
-
3
:]
=
[
stack
[
-
1
],
stack
[
-
3
],
stack
[
-
2
]]
DUP_TOP
:
stack
.
append
(
stack
[
-
1
])
UNARY_POSITIVE
:
UNARY_NEGATIVE
:
UNARY_NOT
:
UNARY_CONVERT
:
UNARY_INVERT
:
stack
[
-
1
:]
=
[
self
]
BINARY_POWER
:
BINARY_MULTIPLY
:
BINARY_DIVIDE
:
BINARY_MODULO
:
BINARY_ADD
:
BINARY_SUBTRACT
:
BINARY_SUBSCR
:
BINARY_LSHIFT
:
BINARY_RSHIFT
:
BINARY_AND
:
BINARY_XOR
:
BINARY_OR
:
stack
[
-
2
:]
=
[
self
]
SLICE_0
:
stack
[
-
1
:]
=
[
self
]
SLICE_1
:
SLICE_2
:
stack
[
-
2
:]
=
[
self
]
SLICE_3
:
stack
[
-
3
:]
=
[
self
]
STORE_SLICE_0
:
del
stack
[
-
2
:]
STORE_SLICE_1
:
STORE_SLICE_2
:
del
stack
[
-
3
:]
STORE_SLICE_3
:
del
stack
[
-
4
:]
DELETE_SLICE_0
:
del
stack
[
-
1
:]
DELETE_SLICE_1
:
DELETE_SLICE_2
:
del
stack
[
-
2
:]
DELETE_SLICE_3
:
del
stack
[
-
3
:]
STORE_SUBSCR
:
del
stack
[
-
3
:]
DELETE_SUBSCR
:
del
stack
[
-
2
:]
PRINT_EXPR
:
PRINT_ITEM
:
stack
.
pop
()
PRINT_NEWLINE
:
pass
BREAK_LOOP
:
raise
"No jumps here!"
LOAD_LOCALS
:
stack
.
append
(
self
)
RETURN_VALUE
:
stack
[:]
=
[]
EXEC_STMT
:
pass
POP_BLOCK
:
pass
END_FINALLY
:
pass
BUILD_CLASS
:
stack
[
-
3
:]
=
[
self
]
STORE_NAME
:
DELETE_NAME
:
stack
.
pop
()
UNPACK_TUPLE
:
UNPACK_LIST
:
stack
.
append
([
self
]
*
self
.
arg
)
STORE_ATTR
:
DELETE_ATTR
:
STORE_GLOBAL
:
DELETE_GLOBAL
:
stack
.
pop
()
LOAD_CONST
:
LOAD_NAME
:
stack
.
append
(
self
)
BUILD_TUPLE
:
BUILD_LIST
:
if
self
.
arg
>
0
:
stack
[
-
self
.
arg
:]
=
[
self
]
else
:
stack
.
append
(
self
)
BUILD_MAP
:
stack
.
append
(
self
)
LOAD_ATTR
:
stack
[
-
1
]
=
self
COMPARE_OP
:
stack
[
-
2
:]
=
[
self
]
# ????
IMPORT_NAME
:
stack
.
append
(
self
)
IMPORT_FROM
:
pass
JUMP_FORWARD
:
JUMP_IF_TRUE
:
JUMP_IF_FALSE
:
JUMP_ABSOLUTE
:
raise
"jumps not handled here!"
FOR_LOOP
:
raise
"loop alert"
LOAD_GLOBAL
:
stack
.
append
(
self
)
SETUP_LOOP
:
raise
"loop alert!"
SETUP_EXCEPT
:
SETUP_FINALLY
:
pass
# ??
LOAD_FAST
:
stack
.
append
(
self
)
STORE_FAST
:
DELETE_FAST
:
stack
.
pop
()
SET_LINENO
:
pass
RAISE_VARARGS
:
raise
"Exception!"
CALL_FUNCTION
:
num_keyword_args
=
self
.
arg
>>
8
num_regular_args
=
self
.
arg
&
0xFF
stack
[
-
2
*
num_keyword_args
-
num_regular_args
-
1
:]
=
[
self
]
MAKE_FUNCTION
:
stack
[
-
self
.
arg
-
1
:]
=
[
self
]
BUILD_SLICE
:
stack
[
-
self
.
arg
:]
=
[
self
]
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/opexfuncread.py
0 → 100644
View file @
6429477d
import
os
,
string
file
=
open
(
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
'op_execute_methods'
),
'r'
)
lines
=
string
.
split
(
file
.
read
(),
'
\
n
'
)[
1
:]
exec_funcs
=
{}
n
=
len
(
lines
)
for
i
in
range
(
n
):
if
(
not
lines
[
i
])
or
lines
[
i
][
0
]
==
' '
:
continue
j
=
i
body
=
[]
while
j
<
n
:
if
lines
[
j
][
0
]
==
' '
:
while
lines
[
j
]
and
lines
[
j
][
0
]
==
' '
:
body
.
append
(
lines
[
j
])
j
=
j
+
1
break
j
=
j
+
1
body
=
' '
+
string
.
join
(
body
,
'
\
n
'
)
exec_funcs
[
lines
[
i
][:
-
1
]]
=
body
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/regen
0 → 100755
View file @
6429477d
#!/usr/local/bin/python
from
bytecodehacks.code_gen
import
write_ops
write_ops
.
Main
()
lib/python/Products/PythonScripts/zbytecodehacks/code_gen/write_ops.py
0 → 100644
View file @
6429477d
import
dis
,
re
,
sys
,
os
,
string
from
bytecodehacks.code_gen
import
opexfuncread
temphead
=
"""
\
# this file is autogenerated by running
# from bytecodehacks.code_gen import write_ops
# write_ops.Main()
from bytecodehacks import opbases
from bytecodehacks.label import Label
_opbases = opbases
_Label = Label
del Label
del opbases
_bytecodes={}
"""
noargtemplate
=
"""
\
class %(name)s(_opbases.%(base)s):
op = %(index)d
opc = '
\
\
%(index)03o'
def __init__(self,cs=None,code=None):
if cs is not None:
_opbases.%(base)s.__init__(self,cs,code)
def execute(self,stack):
%(exec_body)s
_bytecodes[%(name)s.opc]=%(name)s
"""
argtemplate
=
"""
\
class %(name)s(_opbases.%(base)s):
op = %(index)d
opc = '
\
\
%(index)03o'
def __init__(self,csorarg,code=None):
if code is not None:
_opbases.%(base)s.__init__(self,csorarg,code)
else:
self.user_init(csorarg)
def execute(self,stack):
%(exec_body)s
_bytecodes[%(name)s.opc]=%(name)s
"""
jumptemplate
=
"""
\
class %(name)s(_opbases.%(base)s):
op = %(index)d
opc = '
\
\
%(index)03o'
def __init__(self,csorarg=None,code=None):
if csorarg is not None:
if code is not None:
_opbases.%(base)s.__init__(self,csorarg,code)
else:
self.label = _Label()
self.user_init(csorarg)
else:
self.label = _Label()
def execute(self,stack):
%(exec_body)s
_bytecodes[%(name)s.opc]=%(name)s
"""
idprog
=
re
.
compile
(
'^[_a-zA-Z][_a-zA-Z0-9]*$'
)
notopprog
=
re
.
compile
(
'^<[0-9]+>$'
)
def
main
(
file
=
sys
.
stdout
):
file
.
write
(
temphead
)
trans
=
string
.
maketrans
(
'+'
,
'_'
)
for
index
in
range
(
len
(
dis
.
opname
)):
name
=
string
.
translate
(
dis
.
opname
[
index
],
trans
)
if
notopprog
.
match
(
name
):
continue
if
not
idprog
.
match
(
name
):
name
=
"Opcode_%d"
%
index
s
=
"generating %s ..."
%
name
pad
=
" "
*
(
30
-
len
(
s
))
print
s
,
pad
,
base
=
"GenericOneByteCode"
if
index
<
dis
.
HAVE_ARGUMENT
:
template
=
noargtemplate
base
=
"GenericOneByteCode"
elif
index
in
dis
.
hasjrel
:
template
=
jumptemplate
base
=
"JRel"
elif
index
in
dis
.
hasjabs
:
template
=
jumptemplate
base
=
"JAbs"
elif
index
in
dis
.
hasname
:
template
=
argtemplate
base
=
"NameOpcode"
elif
index
in
dis
.
haslocal
:
template
=
argtemplate
base
=
"LocalOpcode"
else
:
template
=
argtemplate
base
=
"GenericThreeByteCode"
exec_body
=
opexfuncread
.
exec_funcs
[
name
]
file
.
write
(
template
%
locals
())
print
"done"
def
Main
():
from
bytecodehacks
import
__init__
main
(
open
(
os
.
path
.
join
(
os
.
path
.
dirname
(
__init__
.
__file__
),
'ops.py'
),
'w'
))
lib/python/Products/PythonScripts/zbytecodehacks/common.py
0 → 100755
View file @
6429477d
import
new
def
copy_code_with_changes
(
codeobject
,
argcount
=
None
,
nlocals
=
None
,
stacksize
=
None
,
flags
=
None
,
code
=
None
,
consts
=
None
,
names
=
None
,
varnames
=
None
,
filename
=
None
,
name
=
None
,
firstlineno
=
None
,
lnotab
=
None
):
if
argcount
is
None
:
argcount
=
codeobject
.
co_argcount
if
nlocals
is
None
:
nlocals
=
codeobject
.
co_nlocals
if
stacksize
is
None
:
stacksize
=
codeobject
.
co_stacksize
if
flags
is
None
:
flags
=
codeobject
.
co_flags
if
code
is
None
:
code
=
codeobject
.
co_code
if
consts
is
None
:
consts
=
codeobject
.
co_consts
if
names
is
None
:
names
=
codeobject
.
co_names
if
varnames
is
None
:
varnames
=
codeobject
.
co_varnames
if
filename
is
None
:
filename
=
codeobject
.
co_filename
if
name
is
None
:
name
=
codeobject
.
co_name
if
firstlineno
is
None
:
firstlineno
=
codeobject
.
co_firstlineno
if
lnotab
is
None
:
lnotab
=
codeobject
.
co_lnotab
return
new
.
code
(
argcount
,
nlocals
,
stacksize
,
flags
,
code
,
consts
,
names
,
varnames
,
filename
,
name
,
firstlineno
,
lnotab
)
code_attrs
=
[
'argcount'
,
'nlocals'
,
'stacksize'
,
'flags'
,
'code'
,
'consts'
,
'names'
,
'varnames'
,
'filename'
,
'name'
,
'firstlineno'
,
'lnotab'
]
lib/python/Products/PythonScripts/zbytecodehacks/cyclehandle.py
0 → 100755
View file @
6429477d
class
CycleHandle
:
'''CycleHandles are proxies for cycle roots
A CycleHandle subclass should create one or more workers, and pass them
to _set_workers. These workers can then participate in cycles, as long
as deleting all of the worker's attributes will break the cycle. When a
CycleHandle instance goes away, it deletes all attributes of all of
its workers. You could also explicitly call drop_workers.
For example,
>>> class Ham:
... def __del__(self):
... print 'A ham has died!'
...
>>> ct = CycleHandle()
>>> ct._set_workers(Ham(), Ham())
>>> ct._workers[0].ham2 = ct._workers[1]
>>> ct._workers[1].ham1 = ct._workers[0]
>>> del ct
A ham has died!
A ham has died!
'''
_workers
=
()
def
_set_workers
(
self
,
*
workers
):
self
.
__dict__
[
'_workers'
]
=
workers
def
_not_mutable
(
self
,
*
x
):
raise
TypeError
,
'CycleHandle is not mutable'
__delattr__
=
_not_mutable
def
__setattr__
(
self
,
attr
,
val
):
for
worker
in
self
.
_workers
:
if
hasattr
(
worker
,
'__setattr__'
):
return
getattr
(
worker
,
'__setattr__'
)(
attr
,
val
)
_not_mutable_defs
=
(
'__delslice__'
,
'__setslice__'
,
'__delitem__'
,
'__setitem__'
)
def
__getattr__
(
self
,
attr
):
for
worker
in
self
.
_workers
:
if
hasattr
(
worker
,
attr
):
return
getattr
(
worker
,
attr
)
if
attr
in
self
.
_not_mutable_defs
:
return
self
.
_not_mutable
raise
AttributeError
,
attr
def
_drop_workers
(
self
):
for
worker
in
self
.
_workers
:
worker
.
__dict__
.
clear
()
self
.
__dict__
[
'_workers'
]
=
()
def
__del__
(
self
,
drop_workers
=
_drop_workers
):
drop_workers
(
self
)
def
_test
():
import
doctest
,
cyclehandle
return
doctest
.
testmod
(
cyclehandle
)
if
__name__
==
"__main__"
:
_test
()
lib/python/Products/PythonScripts/zbytecodehacks/dbc.py
0 → 100755
View file @
6429477d
from
code_editor
import
Function
from
ops
import
*
import
dis
,
new
,
string
PRECONDITIONS
=
1
POSTCONDITIONS
=
2
INVARIANTS
=
4
EVERYTHING
=
PRECONDITIONS
|
POSTCONDITIONS
|
INVARIANTS
if
__debug__
:
__strength__
=
PRECONDITIONS
|
POSTCONDITIONS
else
:
__strength__
=
0
# TODO: docs, sort out inheritance.
if
__debug__
:
def
add_contracts
(
target_class
,
contract_class
,
strength
=
None
):
if
strength
is
None
:
strength
=
__strength__
newmethods
=
{}
contractmethods
=
contract_class
.
__dict__
if
strength
&
INVARIANTS
:
inv
=
contractmethods
.
get
(
"class_invariants"
,
None
)
for
name
,
meth
in
target_class
.
__dict__
.
items
():
if
strength
&
PRECONDITIONS
:
pre
=
contractmethods
.
get
(
"pre_"
+
name
,
None
)
if
pre
is
not
None
:
meth
=
add_precondition
(
meth
,
pre
)
if
strength
&
POSTCONDITIONS
:
post
=
contractmethods
.
get
(
"post_"
+
name
,
None
)
if
post
is
not
None
:
meth
=
add_postcondition
(
meth
,
post
)
if
(
strength
&
INVARIANTS
)
and
inv
\
and
type
(
meth
)
is
type
(
add_contracts
):
if
name
<>
'__init__'
:
meth
=
add_precondition
(
meth
,
inv
)
meth
=
add_postcondition
(
meth
,
inv
)
newmethods
[
name
]
=
meth
return
new
.
classobj
(
target_class
.
__name__
,
target_class
.
__bases__
,
newmethods
)
def
add_precondition
(
meth
,
cond
):
meth
=
Function
(
meth
)
cond
=
Function
(
cond
)
mcs
=
meth
.
func_code
.
co_code
ccs
=
cond
.
func_code
.
co_code
nlocals
=
len
(
meth
.
func_code
.
co_varnames
)
nconsts
=
len
(
meth
.
func_code
.
co_consts
)
nnames
=
len
(
meth
.
func_code
.
co_names
)
nargs
=
meth
.
func_code
.
co_argcount
retops
=
[]
for
op
in
ccs
:
if
op
.
__class__
is
RETURN_VALUE
:
# RETURN_VALUEs have to be replaced by JUMP_FORWARDs
newop
=
JUMP_FORWARD
()
ccs
[
ccs
.
index
(
op
)]
=
newop
retops
.
append
(
newop
)
elif
op
.
op
in
dis
.
hasname
:
op
.
arg
=
op
.
arg
+
nnames
elif
op
.
op
in
dis
.
haslocal
:
if
op
.
arg
>=
nargs
:
op
.
arg
=
op
.
arg
+
nlocals
elif
op
.
op
in
dis
.
hasconst
:
op
.
arg
=
op
.
arg
+
nconsts
new
=
POP_TOP
()
mcs
.
insert
(
0
,
new
)
mcs
[
0
:
0
]
=
ccs
.
opcodes
for
op
in
retops
:
op
.
label
.
op
=
new
meth
.
func_code
.
co_consts
.
extend
(
cond
.
func_code
.
co_consts
)
meth
.
func_code
.
co_varnames
.
extend
(
cond
.
func_code
.
co_varnames
)
meth
.
func_code
.
co_names
.
extend
(
cond
.
func_code
.
co_names
)
return
meth
.
make_function
()
def
add_postcondition
(
meth
,
cond
):
""" a bit of a monster! """
meth
=
Function
(
meth
)
cond
=
Function
(
cond
)
mcode
=
meth
.
func_code
ccode
=
cond
.
func_code
mcs
=
mcode
.
co_code
ccs
=
ccode
.
co_code
nlocals
=
len
(
mcode
.
co_varnames
)
nconsts
=
len
(
mcode
.
co_consts
)
nnames
=
len
(
mcode
.
co_names
)
nargs
=
ccode
.
co_argcount
cretops
=
[]
Result_index
=
len
(
meth
.
func_code
.
co_varnames
)
mcode
.
co_varnames
.
append
(
'Result'
)
old_refs
=
find_old_refs
(
cond
)
for
op
in
ccs
:
if
op
.
__class__
is
RETURN_VALUE
:
newop
=
JUMP_FORWARD
()
ccs
[
ccs
.
index
(
op
)]
=
newop
cretops
.
append
(
newop
)
elif
op
.
op
in
dis
.
hasname
:
if
cond
.
func_code
.
co_names
[
op
.
arg
]
==
'Result'
\
and
op
.
__class__
is
LOAD_GLOBAL
:
ccs
[
ccs
.
index
(
op
)]
=
LOAD_FAST
(
Result_index
)
else
:
op
.
arg
=
op
.
arg
+
nnames
elif
op
.
op
in
dis
.
haslocal
:
if
op
.
arg
>=
nargs
:
op
.
arg
=
op
.
arg
+
nlocals
+
1
# + 1 for Result
elif
op
.
op
in
dis
.
hasconst
:
op
.
arg
=
op
.
arg
+
nconsts
# lets generate the prologue code to save values for `Old'
# references and point the LOAD_FASTs inserted by
# find_old_refs to the right locations.
prologue
=
[]
for
ref
,
load_op
in
old_refs
:
if
ref
[
0
]
in
mcode
.
co_varnames
:
prologue
.
append
(
LOAD_FAST
(
mcode
.
co_varnames
.
index
(
ref
[
0
])))
else
:
prologue
.
append
(
LOAD_GLOBAL
(
mcode
.
name_index
(
ref
[
0
])))
for
name
in
ref
[
1
:]:
prologue
.
append
(
LOAD_ATTR
(
mcode
.
name_index
(
name
)))
lname
=
string
.
join
(
ref
,
'.'
)
lindex
=
len
(
mcode
.
co_varnames
)
mcode
.
co_varnames
.
append
(
lname
)
prologue
.
append
(
STORE_FAST
(
lindex
))
load_op
.
arg
=
lindex
mcs
[
0
:
0
]
=
prologue
mretops
=
[]
for
op
in
mcs
:
if
op
.
__class__
is
RETURN_VALUE
:
newop
=
JUMP_FORWARD
()
mcs
[
mcs
.
index
(
op
)]
=
newop
mretops
.
append
(
newop
)
n
=
len
(
mcs
)
# insert the condition code
mcs
[
n
:
n
]
=
ccs
.
opcodes
# store the returned value in Result
store_result
=
STORE_FAST
(
Result_index
)
mcs
.
insert
(
n
,
store_result
)
# target the returns in the method to this store
for
op
in
mretops
:
op
.
label
.
op
=
store_result
# the post condition will leave a value on the stack; lose it.
# could just strip off the LOAD_CONST & RETURN_VALLUE at the
# end of the function and scan for RETURN_VALUES in the
# postcondition as a postcondition shouldn't be returning
# things (certainly not other than None).
new
=
POP_TOP
()
mcs
.
append
(
new
)
# redirect returns in the condition to the POP_TOP just
# inserted...
for
op
in
cretops
:
op
.
label
.
op
=
new
# actually return Result...
mcs
.
append
(
LOAD_FAST
(
Result_index
))
mcs
.
append
(
RETURN_VALUE
())
# and add the new constants and names (to avoid core dumps!)
mcode
.
co_consts
.
extend
(
ccode
.
co_consts
)
mcode
.
co_varnames
.
extend
(
ccode
.
co_varnames
)
mcode
.
co_names
.
extend
(
ccode
.
co_names
)
return
meth
.
make_function
()
def
find_old_refs
(
func
):
chaining
=
0
refs
=
[]
ref
=
[]
code
=
func
.
func_code
cs
=
code
.
co_code
i
=
0
while
i
<
len
(
cs
):
op
=
cs
[
i
]
if
not
chaining
:
if
op
.
__class__
is
LOAD_GLOBAL
:
if
code
.
co_names
[
op
.
arg
]
==
'Old'
:
chaining
=
1
else
:
if
op
.
__class__
is
LOAD_ATTR
:
ref
.
append
(
code
.
co_names
[
op
.
arg
])
else
:
newop
=
LOAD_FAST
(
0
)
cs
[
i
-
len
(
ref
)
-
1
:
i
]
=
[
newop
]
i
=
i
-
len
(
ref
)
refs
.
append
((
ref
,
newop
))
ref
=
[]
chaining
=
0
i
=
i
+
1
return
refs
else
:
# if not __debug__
def
add_contracts
(
target_class
,
contracts_class
):
return
target_class
# example
class
Uncontracted
:
def
__init__
(
self
,
x
,
y
):
self
.
x
=
x
self
.
y
=
y
def
do
(
self
):
# self.x = self.x + 1 # sneaky!
return
self
.
x
/
self
.
y
class
Contracts
:
def
pre___init__
(
self
,
x
,
y
):
assert
y
<>
0
def
post_do
(
self
):
assert
Old
.
self
.
x
==
self
.
x
assert
Old
.
self
.
y
==
self
.
y
assert
Result
>
0
,
"Result was %s"
%
`Result`
def
class_invariants
(
self
):
assert
self
.
x
>
0
Contracted
=
add_contracts
(
Uncontracted
,
Contracts
)
lib/python/Products/PythonScripts/zbytecodehacks/find_function_call.py
0 → 100755
View file @
6429477d
from
code_editor
import
Function
from
ops
import
*
def
find_function_call
(
infunc
,
calledfuncname
,
allowkeywords
=
0
,
startindex
=
0
):
i
=
startindex
code
=
infunc
.
func_code
cs
=
code
.
co_code
def
match
(
op
,
name
=
calledfuncname
):
return
getattr
(
op
,
'name'
,
None
)
==
name
while
i
<
len
(
cs
):
op
=
code
.
co_code
[
i
]
if
match
(
op
):
try
:
if
allowkeywords
:
return
simulate_stack_with_keywords
(
code
,
i
)
else
:
return
simulate_stack
(
code
,
i
)
except
:
i
=
i
+
1
i
=
i
+
1
if
allowkeywords
:
return
None
,
0
else
:
return
None
def
call_stack_length_usage
(
arg
):
num_keyword_args
=
arg
>>
8
num_regular_args
=
arg
&
0xFF
return
2
*
num_keyword_args
+
num_regular_args
def
simulate_stack
(
code
,
index_start
):
stack
=
[]
cs
=
code
.
co_code
i
,
n
=
index_start
,
len
(
cs
)
while
i
<
n
:
op
=
cs
[
i
]
if
op
.
__class__
is
CALL_FUNCTION
and
op
.
arg
+
1
==
len
(
stack
):
stack
.
append
(
op
)
return
stack
elif
op
.
is_jump
():
i
=
cs
.
index
(
op
.
label
.
op
)
+
1
else
:
op
.
execute
(
stack
)
i
=
i
+
1
raise
"no call found!"
def
simulate_stack_with_keywords
(
code
,
index_start
):
stack
=
[]
cs
=
code
.
co_code
i
,
n
=
index_start
,
len
(
cs
)
while
i
<
n
:
op
=
cs
[
i
]
if
op
.
__class__
is
CALL_FUNCTION
\
and
call_stack_length_usage
(
op
.
arg
)
+
1
==
len
(
stack
):
stack
.
append
(
op
)
return
stack
,
op
.
arg
>>
8
elif
op
.
is_jump
():
i
=
cs
.
index
(
op
.
label
.
op
)
+
1
else
:
op
.
execute
(
stack
)
i
=
i
+
1
raise
"no call found!"
lib/python/Products/PythonScripts/zbytecodehacks/iif.py
0 → 100755
View file @
6429477d
from
code_editor
import
Function
from
ops
import
*
from
find_function_call
import
find_function_call
def
iifize
(
func
):
func
=
Function
(
func
)
cs
=
func
.
func_code
.
co_code
while
1
:
stack
=
find_function_call
(
func
,
"iif"
)
if
stack
is
None
:
break
load
,
test
,
consequent
,
alternative
,
call
=
stack
cs
.
remove
(
load
)
jump1
=
JUMP_IF_FALSE
(
alternative
)
cs
.
insert
(
cs
.
index
(
test
)
+
1
,
jump1
)
jump2
=
JUMP_FORWARD
(
call
)
cs
.
insert
(
cs
.
index
(
consequent
)
+
1
,
jump2
)
cs
.
remove
(
call
)
cs
=
None
return
func
.
make_function
()
lib/python/Products/PythonScripts/zbytecodehacks/inline.py
0 → 100755
View file @
6429477d
import
dis
from
code_editor
import
Function
from
find_function_call
import
find_function_call
from
ops
import
\
LOAD_GLOBAL
,
RETURN_VALUE
,
SET_LINENO
,
CALL_FUNCTION
,
\
JUMP_FORWARD
,
STORE_FAST
INLINE_MAX_DEPTH
=
100
def
inline
(
func
,
**
funcs
):
func
=
Function
(
func
)
code
=
func
.
func_code
for
name
,
function
in
funcs
.
items
():
count
=
inline1
(
func
,
name
,
function
)
if
count
<>
0
:
fcode
=
function
.
func_code
code
.
co_consts
=
code
.
co_consts
+
list
(
fcode
.
co_consts
)
code
.
co_varnames
=
code
.
co_varnames
+
list
(
fcode
.
co_varnames
)
code
.
co_names
=
code
.
co_names
+
list
(
fcode
.
co_names
)
code
.
co_stacksize
=
code
.
co_stacksize
+
fcode
.
co_stacksize
return
func
.
make_function
()
def
munge_code
(
function
,
code
):
f
=
Function
(
function
)
fcs
=
f
.
func_code
.
co_code
i
,
n
=
0
,
len
(
fcs
)
retops
=
[]
while
i
<
n
:
op
=
fcs
[
i
]
if
op
.
__class__
is
RETURN_VALUE
:
# RETURN_VALUEs have to be replaced by JUMP_FORWARDs
newop
=
JUMP_FORWARD
()
fcs
[
i
]
=
newop
retops
.
append
(
newop
)
elif
op
.
op
in
dis
.
hasname
:
op
.
arg
=
op
.
arg
+
len
(
code
.
co_names
)
elif
op
.
op
in
dis
.
haslocal
:
op
.
arg
=
op
.
arg
+
len
(
code
.
co_varnames
)
elif
op
.
op
in
dis
.
hasconst
:
op
.
arg
=
op
.
arg
+
len
(
code
.
co_consts
)
# should we hack out SET_LINENOs? doesn't seem worth it.
i
=
i
+
1
return
fcs
.
opcodes
,
retops
def
inline1
(
func
,
funcname
,
function
):
code
=
func
.
func_code
cs
=
code
.
co_code
count
=
0
defaults_added
=
0
while
count
<
INLINE_MAX_DEPTH
:
stack
,
numkeywords
=
find_function_call
(
func
,
funcname
,
allowkeywords
=
1
)
if
stack
is
None
:
return
count
count
=
count
+
1
load_func
,
posargs
,
kwargs
,
function_call
=
\
stack
[
0
],
stack
[
1
:
-
2
*
numkeywords
-
1
],
stack
[
-
2
*
numkeywords
-
1
:
-
1
],
stack
[
-
1
]
kw
=
{}
for
i
in
range
(
0
,
len
(
kwargs
),
2
):
name
=
code
.
co_consts
[
kwargs
[
i
].
arg
]
valuesrc
=
kwargs
[
i
+
1
]
kw
[
name
]
=
valuesrc
varnames
=
list
(
function
.
func_code
.
co_varnames
)
for
i
in
kw
.
keys
():
if
i
in
varnames
:
if
varnames
.
index
(
i
)
<
len
(
posargs
):
raise
TypeError
,
"keyword parameter redefined"
else
:
raise
TypeError
,
"unexpected keyword argument: %s"
%
i
# no varargs yet!
# flags = function.func_code.co_flags
# varargs = flags & (1<<2)
# varkeys = flags & (1<<3)
args_got
=
len
(
kw
)
+
len
(
posargs
)
args_expected
=
function
.
func_code
.
co_argcount
if
args_got
>
args_expected
:
raise
TypeError
,
"too many arguments; expected %d, got %d"
%
(
ac
,
len
(
lf
)
+
len
(
posargs
))
elif
args_got
<
args_expected
:
# default args?
raise
TypeError
,
"not enough arguments; expected %d, got %d"
%
(
ac
,
len
(
lf
)
+
len
(
posargs
))
cs
.
remove
(
load_func
)
local_index
=
len
(
code
.
co_varnames
)
for
insn
in
posargs
:
new
=
STORE_FAST
(
local_index
)
cs
.
insert
(
cs
.
index
(
insn
)
+
1
,
new
)
labels
=
cs
.
find_labels
(
cs
.
index
(
new
)
+
1
)
for
label
in
labels
:
label
.
op
=
new
local_index
=
local_index
+
1
for
name
,
insn
in
kw
.
items
():
new
=
STORE_FAST
(
varnames
.
index
(
name
)
+
len
(
code
.
co_varnames
))
cs
.
insert
(
cs
.
index
(
insn
)
+
1
,
new
)
labels
=
cs
.
find_labels
(
cs
.
index
(
new
)
+
1
)
for
label
in
labels
:
label
.
op
=
new
newops
,
retops
=
munge_code
(
function
,
code
)
call_index
=
cs
.
index
(
function_call
)
nextop
=
cs
[
call_index
+
1
]
cs
[
call_index
:
call_index
+
1
]
=
newops
for
op
in
retops
:
op
.
label
.
op
=
nextop
raise
RuntimeError
,
"are we trying to inline a recursive function here?"
lib/python/Products/PythonScripts/zbytecodehacks/label.py
0 → 100755
View file @
6429477d
import
struct
class
Label
:
def
__init__
(
self
,
byte
=
None
):
self
.
byte
=
byte
self
.
__op
=
None
self
.
absrefs
=
[]
self
.
relrefs
=
[]
def
resolve
(
self
,
code
):
self
.
__op
=
code
.
opcodes
[
code
.
byte2op
[
self
.
byte
]]
def
add_absref
(
self
,
byte
):
# request that the absolute address of self.op be written to
# the argument of the opcode starting at byte in the
# codestring
self
.
absrefs
.
append
(
byte
)
def
add_relref
(
self
,
byte
):
# request that the relative address of self.op be written to
# the argument of the opcode starting at byte in the
# codestring
self
.
relrefs
.
append
(
byte
)
def
__setattr__
(
self
,
attr
,
value
):
if
attr
==
'op'
:
self
.
__op
=
value
else
:
self
.
__dict__
[
attr
]
=
value
def
__getattr__
(
self
,
attr
):
if
attr
==
'op'
:
return
self
.
__op
else
:
raise
AttributeError
,
attr
def
write_refs
(
self
,
cs
):
address
=
self
.
__op
.
byte
for
byte
in
self
.
absrefs
:
cs
.
seek
(
byte
+
1
)
cs
.
write
(
struct
.
pack
(
'<h'
,
address
))
for
byte
in
self
.
relrefs
:
offset
=
address
-
byte
-
3
cs
.
seek
(
byte
+
1
)
cs
.
write
(
struct
.
pack
(
'<h'
,
offset
))
lib/python/Products/PythonScripts/zbytecodehacks/macro.py
0 → 100755
View file @
6429477d
import
dis
from
code_editor
import
Function
from
find_function_call
import
find_function_call
from
ops
import
*
MAX_MACRO_DEPTH
=
100
_macros
=
{}
def
add_macro
(
arg1
,
arg2
=
None
):
if
arg2
is
None
:
_macros
[
arg1
.
func_name
]
=
arg1
else
:
_macros
[
arg1
]
=
arg2
def
expand
(
func
,
macros
=
None
):
func
=
Function
(
func
)
code
=
func
.
func_code
if
macros
is
None
:
macros
=
_macros
insertions
=
{}
trips
=
0
while
trips
<
MAX_MACRO_DEPTH
:
outercount
=
0
for
name
,
macro
in
macros
.
items
():
count
=
expand1
(
func
,
name
,
macro
)
outercount
=
outercount
+
count
if
count
<>
0
and
not
insertions
.
has_key
(
macro
):
fcode
=
macro
.
func_code
code
.
co_consts
=
code
.
co_consts
+
list
(
fcode
.
co_consts
)
code
.
co_varnames
=
code
.
co_varnames
+
list
(
fcode
.
co_varnames
)
code
.
co_names
=
code
.
co_names
+
list
(
fcode
.
co_names
)
code
.
co_stacksize
=
code
.
co_stacksize
+
fcode
.
co_stacksize
insertions
[
macro
]
=
0
if
not
outercount
:
return
func
.
make_function
()
trips
=
trips
+
1
raise
RuntimeError
,
"unbounded recursion?!"
def
expand_these
(
func
,
**
macros
):
return
expand
(
func
,
macros
)
def
remove_epilogue
(
cs
):
try
:
last
,
butone
,
buttwo
=
cs
[
-
3
:]
except
:
return
if
last
.
__class__
is
buttwo
.
__class__
is
RETURN_VALUE
:
if
butone
.
__class__
is
LOAD_CONST
:
if
cs
.
code
.
co_consts
[
butone
.
arg
]
is
None
:
if
not
(
cs
.
find_labels
(
-
1
)
or
cs
.
find_labels
(
-
2
)):
del
cs
[
-
2
:]
def
munge_code
(
function
,
code
,
imported_locals
):
f
=
Function
(
function
)
fcs
=
f
.
func_code
.
co_code
if
fcs
[
0
].
__class__
is
SET_LINENO
:
del
fcs
[
1
:
1
+
2
*
len
(
imported_locals
)]
else
:
del
fcs
[
0
:
2
*
len
(
imported_locals
)]
# a nicety: let's see if the last couple of opcodes are necessary
# (Python _always_ adds a LOAD_CONST None, RETURN_VALUE to the end
# of a function, and I'd like to get rid of that if we can).
remove_epilogue
(
fcs
)
i
,
n
=
0
,
len
(
fcs
)
retops
=
[]
while
i
<
n
:
op
=
fcs
[
i
]
if
op
.
__class__
is
RETURN_VALUE
:
# RETURN_VALUEs have to be replaced by JUMP_FORWARDs
newop
=
JUMP_FORWARD
()
fcs
[
i
]
=
newop
retops
.
append
(
newop
)
elif
op
.
op
in
dis
.
hasname
:
op
.
arg
=
op
.
arg
+
len
(
code
.
co_names
)
elif
op
.
op
in
dis
.
haslocal
:
localname
=
f
.
func_code
.
co_varnames
[
op
.
arg
]
op
.
arg
=
imported_locals
.
get
(
localname
,
op
.
arg
+
len
(
code
.
co_varnames
))
elif
op
.
op
in
dis
.
hasconst
:
op
.
arg
=
op
.
arg
+
len
(
code
.
co_consts
)
# should we hack out SET_LINENOs? doesn't seem worth it.
i
=
i
+
1
return
fcs
.
opcodes
,
retops
def
expand1
(
func
,
name
,
macro
):
code
=
func
.
func_code
cs
=
code
.
co_code
count
=
0
macrocode
=
macro
.
func_code
while
count
<
MAX_MACRO_DEPTH
:
stack
=
find_function_call
(
func
,
name
)
if
stack
is
None
:
return
count
count
=
count
+
1
load_func
,
args
,
function_call
=
\
stack
[
0
],
stack
[
1
:
-
1
],
stack
[
-
1
]
args_got
=
len
(
args
)
args_expected
=
macrocode
.
co_argcount
if
args_got
>
args_expected
:
raise
TypeError
,
"too many arguments; expected %d, got %d"
%
(
args_expected
,
args_got
)
elif
args_got
<
args_expected
:
# default args?
raise
TypeError
,
"not enough arguments; expected %d, got %d"
%
(
args_expected
,
args_got
)
cs
.
remove
(
load_func
)
arg_names
=
macrocode
.
co_varnames
[:
macrocode
.
co_argcount
]
import_args
=
[]
normal_args
=
[]
for
i
in
range
(
len
(
arg_names
)):
if
arg_names
[
i
][
0
]
==
'.'
:
import_args
.
append
(
args
[
i
])
else
:
normal_args
.
append
(
args
[
i
])
imported_locals
=
{}
for
insn
in
import_args
:
cs
.
remove
(
insn
)
if
insn
.
__class__
is
LOAD_GLOBAL
:
name
=
code
.
co_names
[
insn
.
arg
]
var
=
global_to_local
(
code
,
name
)
elif
insn
.
__class__
is
not
LOAD_FAST
:
raise
TypeError
,
"imported arg must be local"
else
:
var
=
insn
.
arg
argindex
=
macrocode
.
co_argcount
+
import_args
.
index
(
insn
)
argname
=
macrocode
.
co_varnames
[
argindex
]
imported_locals
[
argname
]
=
var
local_index
=
len
(
code
.
co_varnames
)
for
insn
in
normal_args
:
new
=
STORE_FAST
(
local_index
+
args
.
index
(
insn
))
cs
.
insert
(
cs
.
index
(
insn
)
+
1
,
new
)
labels
=
cs
.
find_labels
(
cs
.
index
(
new
)
+
1
)
for
label
in
labels
:
label
.
op
=
new
newops
,
retops
=
munge_code
(
macro
,
code
,
imported_locals
)
call_index
=
cs
.
index
(
function_call
)
nextop
=
cs
[
call_index
+
1
]
cs
[
call_index
:
call_index
+
1
]
=
newops
for
op
in
retops
:
if
cs
.
index
(
nextop
)
-
cs
.
index
(
op
)
==
1
:
cs
.
remove
(
op
)
else
:
op
.
label
.
op
=
nextop
raise
RuntimeError
,
"are we trying to expand a recursive macro here?"
def
global_to_local
(
code
,
name
):
"""
\
internal function to make a global variable into
a local one, for the case that setq is the first
reference to a variable.
Modifies a code object in-place.
Return value is index into variable table
"""
cs
=
code
.
co_code
index
=
len
(
code
.
co_varnames
)
code
.
co_varnames
.
append
(
name
)
for
i
in
range
(
len
(
cs
)):
op
=
cs
[
i
]
if
op
.
__class__
not
in
[
LOAD_GLOBAL
,
STORE_GLOBAL
]:
continue
thisname
=
code
.
co_names
[
op
.
arg
]
if
thisname
<>
name
:
continue
if
op
.
__class__
is
LOAD_GLOBAL
:
cs
[
i
]
=
LOAD_FAST
(
index
)
else
:
cs
[
i
]
=
STORE_FAST
(
index
)
return
index
lib/python/Products/PythonScripts/zbytecodehacks/macros.py
0 → 100755
View file @
6429477d
from
macro
import
add_macro
def
main
():
def
setq
((
x
),
v
):
x
=
v
return
v
add_macro
(
setq
)
def
pre_incr
((
x
)):
x
=
x
+
1
return
x
add_macro
(
pre_incr
)
def
post_incr
((
x
)):
t
=
x
x
=
x
+
1
return
t
add_macro
(
post_incr
)
def
pre_decr
((
x
)):
x
=
x
-
1
return
x
add_macro
(
pre_decr
)
def
post_decr
((
x
)):
t
=
x
x
=
x
+
1
return
t
add_macro
(
post_decr
)
def
add_set
((
x
),
v
):
x
=
x
+
v
return
x
add_macro
(
add_set
)
def
sub_set
((
x
),
v
):
x
=
x
-
v
return
x
add_macro
(
sub_set
)
def
mul_set
((
x
),
v
):
x
=
x
*
v
return
x
add_macro
(
mul_set
)
def
div_set
((
x
),
v
):
x
=
x
/
v
return
x
add_macro
(
div_set
)
def
mod_set
((
x
),
v
):
x
=
x
%
v
return
x
add_macro
(
mod_set
)
main
()
def
test
():
from
macro
import
expand
def
f
(
x
):
i
=
0
while
pre_incr
(
i
)
<
len
(
x
):
if
setq
(
c
,
x
[
i
])
==
3
:
print
c
,
42
x
=
expand
(
f
)
return
x
x
(
range
(
10
))
lib/python/Products/PythonScripts/zbytecodehacks/opbases.py
0 → 100755
View file @
6429477d
import
struct
,
dis
,
new
from
label
import
Label
class
ByteCode
:
pass
class
GenericOneByteCode
(
ByteCode
):
def
__init__
(
self
,
cs
,
code
):
pass
def
__repr__
(
self
):
return
self
.
__class__
.
__name__
def
assemble
(
self
,
code
):
return
self
.
opc
def
is_jump
(
self
):
return
0
def
has_name
(
self
):
return
0
def
has_name_or_local
(
self
):
return
self
.
has_name
()
or
self
.
has_local
()
def
has_local
(
self
):
return
0
class
GenericThreeByteCode
(
GenericOneByteCode
):
def
__init__
(
self
,
cs
,
code
):
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
arg
=
cs
.
read
(
2
)
self
.
arg
=
struct
.
unpack
(
'<h'
,
arg
)[
0
]
def
__repr__
(
self
):
return
"%s %d"
%
(
self
.
__class__
.
__name__
,
self
.
arg
)
def
assemble
(
self
,
code
):
return
self
.
opc
+
struct
.
pack
(
'<h'
,
self
.
arg
)
def
user_init
(
self
,
arg
):
self
.
arg
=
arg
class
Jump
(
GenericThreeByteCode
):
def
__repr__
(
self
):
return
"%s %s"
%
(
self
.
__class__
.
__name__
,
`self.label`
)
def
is_jump
(
self
):
return
1
def
user_init
(
self
,
arg
):
self
.
label
.
op
=
arg
class
JRel
(
Jump
):
def
__init__
(
self
,
cs
,
code
):
GenericThreeByteCode
.
__init__
(
self
,
cs
,
code
)
self
.
label
=
Label
(
cs
.
tell
()
+
self
.
arg
)
code
.
add_label
(
self
.
label
)
def
assemble
(
self
,
code
):
self
.
label
.
add_relref
(
self
.
byte
)
return
self
.
opc
+
'
\
000
\
000
'
class
JAbs
(
Jump
):
def
__init__
(
self
,
cs
,
code
):
GenericThreeByteCode
.
__init__
(
self
,
cs
,
code
)
self
.
label
=
Label
(
self
.
arg
)
code
.
add_label
(
self
.
label
)
def
assemble
(
self
,
code
):
self
.
label
.
add_absref
(
self
.
byte
)
return
self
.
opc
+
'
\
000
\
000
'
class
_NamedOpcode
(
GenericThreeByteCode
):
def
user_init
(
self
,
arg
):
if
type
(
arg
)
==
type
(
1
):
self
.
arg
=
arg
else
:
self
.
name
=
arg
def
__repr__
(
self
):
if
hasattr
(
self
,
"name"
):
return
"%s : %s"
%
(
self
.
__class__
.
__name__
,
self
.
name
)
else
:
return
"%s : %d"
%
(
self
.
__class__
.
__name__
,
self
.
arg
)
class
NameOpcode
(
_NamedOpcode
):
def
__init__
(
self
,
cs
,
code
):
GenericThreeByteCode
.
__init__
(
self
,
cs
,
code
)
self
.
name
=
code
.
code
.
co_names
[
self
.
arg
]
def
has_name
(
self
):
return
1
def
assemble
(
self
,
code
):
if
hasattr
(
self
,
"name"
)
and
not
hasattr
(
self
,
"arg"
):
self
.
arg
=
code
.
code
.
name_index
(
self
.
name
)
return
GenericThreeByteCode
.
assemble
(
self
,
code
)
class
LocalOpcode
(
_NamedOpcode
):
def
__init__
(
self
,
cs
,
code
):
GenericThreeByteCode
.
__init__
(
self
,
cs
,
code
)
self
.
name
=
code
.
code
.
co_varnames
[
self
.
arg
]
def
has_local
(
self
):
return
1
def
assemble
(
self
,
code
):
if
hasattr
(
self
,
"name"
)
and
not
hasattr
(
self
,
"arg"
):
self
.
arg
=
code
.
code
.
local_index
(
self
.
name
)
return
GenericThreeByteCode
.
assemble
(
self
,
code
)
lib/python/Products/PythonScripts/zbytecodehacks/ops.py
0 → 100755
View file @
6429477d
# this file is autogenerated by running
# from bytecodehacks.code_gen import write_ops
# write_ops.Main()
import
opbases
from
label
import
Label
_opbases
=
opbases
_Label
=
Label
del
Label
del
opbases
_bytecodes
=
{}
class
STOP_CODE
(
_opbases
.
GenericOneByteCode
):
op
=
0
opc
=
'
\
000
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
pass
_bytecodes
[
STOP_CODE
.
opc
]
=
STOP_CODE
class
POP_TOP
(
_opbases
.
GenericOneByteCode
):
op
=
1
opc
=
'
\
001
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
POP_TOP
.
opc
]
=
POP_TOP
class
ROT_TWO
(
_opbases
.
GenericOneByteCode
):
op
=
2
opc
=
'
\
002
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
stack
[
-
1
],
stack
[
-
2
]]
_bytecodes
[
ROT_TWO
.
opc
]
=
ROT_TWO
class
ROT_THREE
(
_opbases
.
GenericOneByteCode
):
op
=
3
opc
=
'
\
003
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
3
:]
=
[
stack
[
-
1
],
stack
[
-
3
],
stack
[
-
2
]]
_bytecodes
[
ROT_THREE
.
opc
]
=
ROT_THREE
class
DUP_TOP
(
_opbases
.
GenericOneByteCode
):
op
=
4
opc
=
'
\
004
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
.
append
(
stack
[
-
1
])
_bytecodes
[
DUP_TOP
.
opc
]
=
DUP_TOP
class
UNARY_POSITIVE
(
_opbases
.
GenericOneByteCode
):
op
=
10
opc
=
'
\
012
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
1
:]
=
[
self
]
_bytecodes
[
UNARY_POSITIVE
.
opc
]
=
UNARY_POSITIVE
class
UNARY_NEGATIVE
(
_opbases
.
GenericOneByteCode
):
op
=
11
opc
=
'
\
013
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
1
:]
=
[
self
]
_bytecodes
[
UNARY_NEGATIVE
.
opc
]
=
UNARY_NEGATIVE
class
UNARY_NOT
(
_opbases
.
GenericOneByteCode
):
op
=
12
opc
=
'
\
014
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
1
:]
=
[
self
]
_bytecodes
[
UNARY_NOT
.
opc
]
=
UNARY_NOT
class
UNARY_CONVERT
(
_opbases
.
GenericOneByteCode
):
op
=
13
opc
=
'
\
015
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
1
:]
=
[
self
]
_bytecodes
[
UNARY_CONVERT
.
opc
]
=
UNARY_CONVERT
class
UNARY_INVERT
(
_opbases
.
GenericOneByteCode
):
op
=
15
opc
=
'
\
017
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
1
:]
=
[
self
]
_bytecodes
[
UNARY_INVERT
.
opc
]
=
UNARY_INVERT
class
BINARY_POWER
(
_opbases
.
GenericOneByteCode
):
op
=
19
opc
=
'
\
023
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_POWER
.
opc
]
=
BINARY_POWER
class
BINARY_MULTIPLY
(
_opbases
.
GenericOneByteCode
):
op
=
20
opc
=
'
\
024
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_MULTIPLY
.
opc
]
=
BINARY_MULTIPLY
class
BINARY_DIVIDE
(
_opbases
.
GenericOneByteCode
):
op
=
21
opc
=
'
\
025
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_DIVIDE
.
opc
]
=
BINARY_DIVIDE
class
BINARY_MODULO
(
_opbases
.
GenericOneByteCode
):
op
=
22
opc
=
'
\
026
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_MODULO
.
opc
]
=
BINARY_MODULO
class
BINARY_ADD
(
_opbases
.
GenericOneByteCode
):
op
=
23
opc
=
'
\
027
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_ADD
.
opc
]
=
BINARY_ADD
class
BINARY_SUBTRACT
(
_opbases
.
GenericOneByteCode
):
op
=
24
opc
=
'
\
030
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_SUBTRACT
.
opc
]
=
BINARY_SUBTRACT
class
BINARY_SUBSCR
(
_opbases
.
GenericOneByteCode
):
op
=
25
opc
=
'
\
031
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_SUBSCR
.
opc
]
=
BINARY_SUBSCR
class
SLICE_0
(
_opbases
.
GenericOneByteCode
):
op
=
30
opc
=
'
\
036
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
1
:]
=
[
self
]
_bytecodes
[
SLICE_0
.
opc
]
=
SLICE_0
class
SLICE_1
(
_opbases
.
GenericOneByteCode
):
op
=
31
opc
=
'
\
037
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
SLICE_1
.
opc
]
=
SLICE_1
class
SLICE_2
(
_opbases
.
GenericOneByteCode
):
op
=
32
opc
=
'
\
040
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
SLICE_2
.
opc
]
=
SLICE_2
class
SLICE_3
(
_opbases
.
GenericOneByteCode
):
op
=
33
opc
=
'
\
041
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
3
:]
=
[
self
]
_bytecodes
[
SLICE_3
.
opc
]
=
SLICE_3
class
STORE_SLICE_0
(
_opbases
.
GenericOneByteCode
):
op
=
40
opc
=
'
\
050
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
2
:]
_bytecodes
[
STORE_SLICE_0
.
opc
]
=
STORE_SLICE_0
class
STORE_SLICE_1
(
_opbases
.
GenericOneByteCode
):
op
=
41
opc
=
'
\
051
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
3
:]
_bytecodes
[
STORE_SLICE_1
.
opc
]
=
STORE_SLICE_1
class
STORE_SLICE_2
(
_opbases
.
GenericOneByteCode
):
op
=
42
opc
=
'
\
052
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
3
:]
_bytecodes
[
STORE_SLICE_2
.
opc
]
=
STORE_SLICE_2
class
STORE_SLICE_3
(
_opbases
.
GenericOneByteCode
):
op
=
43
opc
=
'
\
053
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
4
:]
_bytecodes
[
STORE_SLICE_3
.
opc
]
=
STORE_SLICE_3
class
DELETE_SLICE_0
(
_opbases
.
GenericOneByteCode
):
op
=
50
opc
=
'
\
062
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
1
:]
_bytecodes
[
DELETE_SLICE_0
.
opc
]
=
DELETE_SLICE_0
class
DELETE_SLICE_1
(
_opbases
.
GenericOneByteCode
):
op
=
51
opc
=
'
\
063
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
2
:]
_bytecodes
[
DELETE_SLICE_1
.
opc
]
=
DELETE_SLICE_1
class
DELETE_SLICE_2
(
_opbases
.
GenericOneByteCode
):
op
=
52
opc
=
'
\
064
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
2
:]
_bytecodes
[
DELETE_SLICE_2
.
opc
]
=
DELETE_SLICE_2
class
DELETE_SLICE_3
(
_opbases
.
GenericOneByteCode
):
op
=
53
opc
=
'
\
065
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
3
:]
_bytecodes
[
DELETE_SLICE_3
.
opc
]
=
DELETE_SLICE_3
class
STORE_SUBSCR
(
_opbases
.
GenericOneByteCode
):
op
=
60
opc
=
'
\
074
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
3
:]
_bytecodes
[
STORE_SUBSCR
.
opc
]
=
STORE_SUBSCR
class
DELETE_SUBSCR
(
_opbases
.
GenericOneByteCode
):
op
=
61
opc
=
'
\
075
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
del
stack
[
-
2
:]
_bytecodes
[
DELETE_SUBSCR
.
opc
]
=
DELETE_SUBSCR
class
BINARY_LSHIFT
(
_opbases
.
GenericOneByteCode
):
op
=
62
opc
=
'
\
076
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_LSHIFT
.
opc
]
=
BINARY_LSHIFT
class
BINARY_RSHIFT
(
_opbases
.
GenericOneByteCode
):
op
=
63
opc
=
'
\
077
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_RSHIFT
.
opc
]
=
BINARY_RSHIFT
class
BINARY_AND
(
_opbases
.
GenericOneByteCode
):
op
=
64
opc
=
'
\
100
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_AND
.
opc
]
=
BINARY_AND
class
BINARY_XOR
(
_opbases
.
GenericOneByteCode
):
op
=
65
opc
=
'
\
101
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_XOR
.
opc
]
=
BINARY_XOR
class
BINARY_OR
(
_opbases
.
GenericOneByteCode
):
op
=
66
opc
=
'
\
102
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
_bytecodes
[
BINARY_OR
.
opc
]
=
BINARY_OR
class
PRINT_EXPR
(
_opbases
.
GenericOneByteCode
):
op
=
70
opc
=
'
\
106
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
PRINT_EXPR
.
opc
]
=
PRINT_EXPR
class
PRINT_ITEM
(
_opbases
.
GenericOneByteCode
):
op
=
71
opc
=
'
\
107
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
PRINT_ITEM
.
opc
]
=
PRINT_ITEM
class
PRINT_NEWLINE
(
_opbases
.
GenericOneByteCode
):
op
=
72
opc
=
'
\
110
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
pass
_bytecodes
[
PRINT_NEWLINE
.
opc
]
=
PRINT_NEWLINE
class
BREAK_LOOP
(
_opbases
.
GenericOneByteCode
):
op
=
80
opc
=
'
\
120
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
raise
"No jumps here!"
_bytecodes
[
BREAK_LOOP
.
opc
]
=
BREAK_LOOP
class
LOAD_LOCALS
(
_opbases
.
GenericOneByteCode
):
op
=
82
opc
=
'
\
122
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
.
append
(
self
)
_bytecodes
[
LOAD_LOCALS
.
opc
]
=
LOAD_LOCALS
class
RETURN_VALUE
(
_opbases
.
GenericOneByteCode
):
op
=
83
opc
=
'
\
123
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[:]
=
[]
_bytecodes
[
RETURN_VALUE
.
opc
]
=
RETURN_VALUE
class
EXEC_STMT
(
_opbases
.
GenericOneByteCode
):
op
=
85
opc
=
'
\
125
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
pass
_bytecodes
[
EXEC_STMT
.
opc
]
=
EXEC_STMT
class
POP_BLOCK
(
_opbases
.
GenericOneByteCode
):
op
=
87
opc
=
'
\
127
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
pass
_bytecodes
[
POP_BLOCK
.
opc
]
=
POP_BLOCK
class
END_FINALLY
(
_opbases
.
GenericOneByteCode
):
op
=
88
opc
=
'
\
130
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
pass
_bytecodes
[
END_FINALLY
.
opc
]
=
END_FINALLY
class
BUILD_CLASS
(
_opbases
.
GenericOneByteCode
):
op
=
89
opc
=
'
\
131
'
def
__init__
(
self
,
cs
=
None
,
code
=
None
):
if
cs
is
not
None
:
_opbases
.
GenericOneByteCode
.
__init__
(
self
,
cs
,
code
)
def
execute
(
self
,
stack
):
stack
[
-
3
:]
=
[
self
]
_bytecodes
[
BUILD_CLASS
.
opc
]
=
BUILD_CLASS
class
STORE_NAME
(
_opbases
.
NameOpcode
):
op
=
90
opc
=
'
\
132
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
STORE_NAME
.
opc
]
=
STORE_NAME
class
DELETE_NAME
(
_opbases
.
NameOpcode
):
op
=
91
opc
=
'
\
133
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
DELETE_NAME
.
opc
]
=
DELETE_NAME
class
UNPACK_TUPLE
(
_opbases
.
GenericThreeByteCode
):
op
=
92
opc
=
'
\
134
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
append
([
self
]
*
self
.
arg
)
_bytecodes
[
UNPACK_TUPLE
.
opc
]
=
UNPACK_TUPLE
class
UNPACK_LIST
(
_opbases
.
GenericThreeByteCode
):
op
=
93
opc
=
'
\
135
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
append
([
self
]
*
self
.
arg
)
_bytecodes
[
UNPACK_LIST
.
opc
]
=
UNPACK_LIST
class
STORE_ATTR
(
_opbases
.
NameOpcode
):
op
=
95
opc
=
'
\
137
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
STORE_ATTR
.
opc
]
=
STORE_ATTR
class
DELETE_ATTR
(
_opbases
.
NameOpcode
):
op
=
96
opc
=
'
\
140
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
DELETE_ATTR
.
opc
]
=
DELETE_ATTR
class
STORE_GLOBAL
(
_opbases
.
NameOpcode
):
op
=
97
opc
=
'
\
141
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
STORE_GLOBAL
.
opc
]
=
STORE_GLOBAL
class
DELETE_GLOBAL
(
_opbases
.
NameOpcode
):
op
=
98
opc
=
'
\
142
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
DELETE_GLOBAL
.
opc
]
=
DELETE_GLOBAL
class
LOAD_CONST
(
_opbases
.
GenericThreeByteCode
):
op
=
100
opc
=
'
\
144
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
append
(
self
)
_bytecodes
[
LOAD_CONST
.
opc
]
=
LOAD_CONST
class
LOAD_NAME
(
_opbases
.
NameOpcode
):
op
=
101
opc
=
'
\
145
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
append
(
self
)
_bytecodes
[
LOAD_NAME
.
opc
]
=
LOAD_NAME
class
BUILD_TUPLE
(
_opbases
.
GenericThreeByteCode
):
op
=
102
opc
=
'
\
146
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
if
self
.
arg
>
0
:
stack
[
-
self
.
arg
:]
=
[
self
]
else
:
stack
.
append
(
self
)
_bytecodes
[
BUILD_TUPLE
.
opc
]
=
BUILD_TUPLE
class
BUILD_LIST
(
_opbases
.
GenericThreeByteCode
):
op
=
103
opc
=
'
\
147
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
if
self
.
arg
>
0
:
stack
[
-
self
.
arg
:]
=
[
self
]
else
:
stack
.
append
(
self
)
_bytecodes
[
BUILD_LIST
.
opc
]
=
BUILD_LIST
class
BUILD_MAP
(
_opbases
.
GenericThreeByteCode
):
op
=
104
opc
=
'
\
150
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
append
(
self
)
_bytecodes
[
BUILD_MAP
.
opc
]
=
BUILD_MAP
class
LOAD_ATTR
(
_opbases
.
NameOpcode
):
op
=
105
opc
=
'
\
151
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
[
-
1
]
=
self
_bytecodes
[
LOAD_ATTR
.
opc
]
=
LOAD_ATTR
class
COMPARE_OP
(
_opbases
.
GenericThreeByteCode
):
op
=
106
opc
=
'
\
152
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
[
-
2
:]
=
[
self
]
# ????
_bytecodes
[
COMPARE_OP
.
opc
]
=
COMPARE_OP
class
IMPORT_NAME
(
_opbases
.
NameOpcode
):
op
=
107
opc
=
'
\
153
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
append
(
self
)
_bytecodes
[
IMPORT_NAME
.
opc
]
=
IMPORT_NAME
class
IMPORT_FROM
(
_opbases
.
NameOpcode
):
op
=
108
opc
=
'
\
154
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
pass
_bytecodes
[
IMPORT_FROM
.
opc
]
=
IMPORT_FROM
class
JUMP_FORWARD
(
_opbases
.
JRel
):
op
=
110
opc
=
'
\
156
'
def
__init__
(
self
,
csorarg
=
None
,
code
=
None
):
if
csorarg
is
not
None
:
if
code
is
not
None
:
_opbases
.
JRel
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
label
=
_Label
()
self
.
user_init
(
csorarg
)
else
:
self
.
label
=
_Label
()
def
execute
(
self
,
stack
):
raise
"jumps not handled here!"
_bytecodes
[
JUMP_FORWARD
.
opc
]
=
JUMP_FORWARD
class
JUMP_IF_FALSE
(
_opbases
.
JRel
):
op
=
111
opc
=
'
\
157
'
def
__init__
(
self
,
csorarg
=
None
,
code
=
None
):
if
csorarg
is
not
None
:
if
code
is
not
None
:
_opbases
.
JRel
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
label
=
_Label
()
self
.
user_init
(
csorarg
)
else
:
self
.
label
=
_Label
()
def
execute
(
self
,
stack
):
raise
"jumps not handled here!"
_bytecodes
[
JUMP_IF_FALSE
.
opc
]
=
JUMP_IF_FALSE
class
JUMP_IF_TRUE
(
_opbases
.
JRel
):
op
=
112
opc
=
'
\
160
'
def
__init__
(
self
,
csorarg
=
None
,
code
=
None
):
if
csorarg
is
not
None
:
if
code
is
not
None
:
_opbases
.
JRel
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
label
=
_Label
()
self
.
user_init
(
csorarg
)
else
:
self
.
label
=
_Label
()
def
execute
(
self
,
stack
):
raise
"jumps not handled here!"
_bytecodes
[
JUMP_IF_TRUE
.
opc
]
=
JUMP_IF_TRUE
class
JUMP_ABSOLUTE
(
_opbases
.
JAbs
):
op
=
113
opc
=
'
\
161
'
def
__init__
(
self
,
csorarg
=
None
,
code
=
None
):
if
csorarg
is
not
None
:
if
code
is
not
None
:
_opbases
.
JAbs
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
label
=
_Label
()
self
.
user_init
(
csorarg
)
else
:
self
.
label
=
_Label
()
def
execute
(
self
,
stack
):
raise
"jumps not handled here!"
_bytecodes
[
JUMP_ABSOLUTE
.
opc
]
=
JUMP_ABSOLUTE
class
FOR_LOOP
(
_opbases
.
JRel
):
op
=
114
opc
=
'
\
162
'
def
__init__
(
self
,
csorarg
=
None
,
code
=
None
):
if
csorarg
is
not
None
:
if
code
is
not
None
:
_opbases
.
JRel
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
label
=
_Label
()
self
.
user_init
(
csorarg
)
else
:
self
.
label
=
_Label
()
def
execute
(
self
,
stack
):
raise
"loop alert"
_bytecodes
[
FOR_LOOP
.
opc
]
=
FOR_LOOP
class
LOAD_GLOBAL
(
_opbases
.
NameOpcode
):
op
=
116
opc
=
'
\
164
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
NameOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
append
(
self
)
_bytecodes
[
LOAD_GLOBAL
.
opc
]
=
LOAD_GLOBAL
class
SETUP_LOOP
(
_opbases
.
JRel
):
op
=
120
opc
=
'
\
170
'
def
__init__
(
self
,
csorarg
=
None
,
code
=
None
):
if
csorarg
is
not
None
:
if
code
is
not
None
:
_opbases
.
JRel
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
label
=
_Label
()
self
.
user_init
(
csorarg
)
else
:
self
.
label
=
_Label
()
def
execute
(
self
,
stack
):
raise
"loop alert!"
_bytecodes
[
SETUP_LOOP
.
opc
]
=
SETUP_LOOP
class
SETUP_EXCEPT
(
_opbases
.
JRel
):
op
=
121
opc
=
'
\
171
'
def
__init__
(
self
,
csorarg
=
None
,
code
=
None
):
if
csorarg
is
not
None
:
if
code
is
not
None
:
_opbases
.
JRel
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
label
=
_Label
()
self
.
user_init
(
csorarg
)
else
:
self
.
label
=
_Label
()
def
execute
(
self
,
stack
):
pass
# ??
_bytecodes
[
SETUP_EXCEPT
.
opc
]
=
SETUP_EXCEPT
class
SETUP_FINALLY
(
_opbases
.
JRel
):
op
=
122
opc
=
'
\
172
'
def
__init__
(
self
,
csorarg
=
None
,
code
=
None
):
if
csorarg
is
not
None
:
if
code
is
not
None
:
_opbases
.
JRel
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
label
=
_Label
()
self
.
user_init
(
csorarg
)
else
:
self
.
label
=
_Label
()
def
execute
(
self
,
stack
):
pass
# ??
_bytecodes
[
SETUP_FINALLY
.
opc
]
=
SETUP_FINALLY
class
LOAD_FAST
(
_opbases
.
LocalOpcode
):
op
=
124
opc
=
'
\
174
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
LocalOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
append
(
self
)
_bytecodes
[
LOAD_FAST
.
opc
]
=
LOAD_FAST
class
STORE_FAST
(
_opbases
.
LocalOpcode
):
op
=
125
opc
=
'
\
175
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
LocalOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
STORE_FAST
.
opc
]
=
STORE_FAST
class
DELETE_FAST
(
_opbases
.
LocalOpcode
):
op
=
126
opc
=
'
\
176
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
LocalOpcode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
.
pop
()
_bytecodes
[
DELETE_FAST
.
opc
]
=
DELETE_FAST
class
SET_LINENO
(
_opbases
.
GenericThreeByteCode
):
op
=
127
opc
=
'
\
177
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
pass
_bytecodes
[
SET_LINENO
.
opc
]
=
SET_LINENO
class
RAISE_VARARGS
(
_opbases
.
GenericThreeByteCode
):
op
=
130
opc
=
'
\
202
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
raise
"Exception!"
_bytecodes
[
RAISE_VARARGS
.
opc
]
=
RAISE_VARARGS
class
CALL_FUNCTION
(
_opbases
.
GenericThreeByteCode
):
op
=
131
opc
=
'
\
203
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
num_keyword_args
=
self
.
arg
>>
8
num_regular_args
=
self
.
arg
&
0xFF
stack
[
-
2
*
num_keyword_args
-
num_regular_args
-
1
:]
=
[
self
]
_bytecodes
[
CALL_FUNCTION
.
opc
]
=
CALL_FUNCTION
class
MAKE_FUNCTION
(
_opbases
.
GenericThreeByteCode
):
op
=
132
opc
=
'
\
204
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
[
-
self
.
arg
-
1
:]
=
[
self
]
_bytecodes
[
MAKE_FUNCTION
.
opc
]
=
MAKE_FUNCTION
class
BUILD_SLICE
(
_opbases
.
GenericThreeByteCode
):
op
=
133
opc
=
'
\
205
'
def
__init__
(
self
,
csorarg
,
code
=
None
):
if
code
is
not
None
:
_opbases
.
GenericThreeByteCode
.
__init__
(
self
,
csorarg
,
code
)
else
:
self
.
user_init
(
csorarg
)
def
execute
(
self
,
stack
):
stack
[
-
self
.
arg
:]
=
[
self
]
_bytecodes
[
BUILD_SLICE
.
opc
]
=
BUILD_SLICE
lib/python/Products/PythonScripts/zbytecodehacks/rationalize.py
0 → 100755
View file @
6429477d
import
code_editor
from
ops
import
*
import
operator
CONDJUMP
=
[
JUMP_IF_TRUE
,
JUMP_IF_FALSE
]
UNCONDJUMP
=
[
JUMP_FORWARD
,
JUMP_ABSOLUTE
]
UNCOND
=
UNCONDJUMP
+
[
BREAK_LOOP
,
STOP_CODE
,
RETURN_VALUE
,
\
RAISE_VARARGS
]
PYBLOCK
=
[
SETUP_LOOP
,
SETUP_EXCEPT
,
SETUP_FINALLY
]
PYENDBLOCK
=
[
POP_BLOCK
]
binaryops
=
{
'BINARY_ADD'
:
operator
.
add
,
'BINARY_SUBTRACT'
:
operator
.
sub
,
'BINARY_MULTIPLY'
:
operator
.
mul
,
'BINARY_DIVIDE'
:
operator
.
div
,
'BINARY_MODULO'
:
operator
.
mod
,
'BINARY_POWER'
:
pow
,
'BINARY_LSHIFT'
:
operator
.
lshift
,
'BINARY_RSHIFT'
:
operator
.
rshift
,
'BINARY_AND'
:
operator
.
and_
,
'BINARY_OR'
:
operator
.
or_
,
'BINARY_XOR'
:
operator
.
xor
}
unaryops
=
{
'UNARY_POS'
:
operator
.
pos
,
'UNARY_NEG'
:
operator
.
neg
,
'UNARY_NOT'
:
operator
.
not_
}
def
rationalize
(
code
):
calculateConstants
(
code
)
strip_setlineno
(
code
)
simplifyjumps
(
code
)
removeconstjump
(
code
)
simplifyjumps
(
code
)
eliminateUnusedNames
(
code
)
eliminateUnusedLocals
(
code
)
def
calculateConstants
(
co
):
"""Precalculate results of operations involving constants."""
cs
=
co
.
co_code
cc
=
co
.
co_consts
stack
=
[]
i
=
0
while
i
<
len
(
cs
):
op
=
cs
[
i
]
if
binaryops
.
has_key
(
op
.
__class__
.
__name__
):
if
stack
[
-
1
].
__class__
is
stack
[
-
2
].
__class__
is
LOAD_CONST
:
arg1
=
cc
[
stack
[
-
2
].
arg
]
arg2
=
cc
[
stack
[
-
1
].
arg
]
result
=
binaryops
[
op
.
__class__
.
__name__
](
arg1
,
arg2
)
if
result
in
cc
:
arg
=
cc
.
index
(
result
)
else
:
arg
=
len
(
cc
)
cc
.
append
(
result
)
cs
.
remove
(
stack
[
-
2
])
cs
.
remove
(
stack
[
-
1
])
i
=
i
-
2
cs
[
i
]
=
LOAD_CONST
(
arg
)
stack
.
pop
()
stack
.
pop
()
stack
.
append
(
cs
[
i
])
else
:
op
.
execute
(
stack
)
elif
unaryops
.
has_key
(
op
.
__class__
.
__name__
):
if
stack
[
-
1
].
__class__
is
LOAD_CONST
:
arg1
=
cc
[
stack
[
-
1
].
arg
]
result
=
unaryops
[
op
.
__class__
.
__name__
](
arg1
)
if
result
in
cc
:
arg
=
cc
.
index
(
result
)
else
:
arg
=
len
(
cc
)
cc
.
append
(
result
)
cs
.
remove
(
stack
[
-
1
])
i
=
i
-
1
cs
[
i
]
=
LOAD_CONST
(
arg
)
stack
.
pop
()
stack
.
append
(
cs
[
i
])
else
:
op
.
execute
(
stack
)
else
:
# this is almost certainly wrong
try
:
op
.
execute
(
stack
)
except
:
pass
i
=
i
+
1
def
strip_setlineno
(
co
):
"""Take in an EditableCode object and strip the SET_LINENO bytecodes"""
i
=
0
while
i
<
len
(
co
.
co_code
):
op
=
co
.
co_code
[
i
]
if
op
.
__class__
is
SET_LINENO
:
co
.
co_code
.
remove
(
op
)
else
:
i
=
i
+
1
def
simplifyjumps
(
co
):
cs
=
co
.
co_code
i
=
0
pyblockstack
=
[
None
]
loopstack
=
[
None
]
trystack
=
[
None
]
firstlook
=
1
while
i
<
len
(
cs
):
op
=
cs
[
i
]
# new pyblock?
if
firstlook
:
if
op
.
__class__
in
PYBLOCK
:
pyblockstack
.
append
(
op
)
if
op
.
__class__
is
SETUP_LOOP
:
loopstack
.
append
(
op
.
label
.
op
)
else
:
trystack
.
append
(
op
.
label
.
op
)
# end of pyblock?
elif
op
.
__class__
==
POP_BLOCK
:
op2
=
pyblockstack
.
pop
()
if
op2
.
__class__
==
SETUP_LOOP
:
loopstack
.
pop
()
else
:
trystack
.
pop
()
# Is the code inaccessible
if
i
>=
1
:
if
cs
[
i
-
1
].
__class__
in
UNCOND
and
not
(
cs
.
find_labels
(
i
)
or
\
op
.
__class__
in
PYENDBLOCK
):
cs
.
remove
(
op
)
firstlook
=
1
continue
# are we jumping from the statement before?
if
cs
[
i
-
1
].
__class__
in
UNCONDJUMP
:
if
cs
[
i
-
1
].
label
.
op
==
op
:
cs
.
remove
(
cs
[
i
-
1
])
firstlook
=
1
continue
# break before end of loop?
elif
cs
[
i
-
1
].
__class__
==
BREAK_LOOP
:
if
op
.
__class__
==
POP_BLOCK
:
cs
.
remove
(
cs
[
i
-
1
])
firstlook
=
1
continue
# Do we have an unconditional jump to an unconditional jump?
if
op
.
__class__
in
UNCONDJUMP
:
if
op
.
label
.
op
.
__class__
in
UNCONDJUMP
:
refop
=
op
.
label
.
op
if
op
.
__class__
==
JUMP_FORWARD
:
newop
=
JUMP_ABSOLUTE
()
newop
.
label
.
op
=
refop
.
label
.
op
cs
[
i
]
=
newop
else
:
op
.
label
.
op
=
refop
.
label
.
op
firstlook
=
0
continue
# Do we have a conditional jump to a break?
if
op
.
__class__
in
CONDJUMP
and
loopstack
[
-
1
]:
destindex
=
cs
.
index
(
op
.
label
.
op
)
preendindex
=
cs
.
index
(
loopstack
[
-
1
])
-
2
if
cs
[
i
+
2
].
__class__
==
BREAK_LOOP
and
cs
[
preendindex
].
__class__
\
==
POP_TOP
:
if
op
.
__class__
==
JUMP_IF_FALSE
:
newop
=
JUMP_IF_TRUE
()
else
:
newop
=
JUMP_IF_FALSE
()
newop
.
label
.
op
=
cs
[
preendindex
]
cs
[
i
]
=
newop
cs
.
remove
(
cs
[
i
+
1
])
cs
.
remove
(
cs
[
i
+
1
])
cs
.
remove
(
cs
[
i
+
1
])
firstlook
=
0
continue
elif
cs
[
destindex
+
1
].
__class__
==
BREAK_LOOP
and
\
cs
[
preendindex
].
__class__
==
POP_TOP
:
op
.
label
.
op
=
cs
[
preendindex
]
cs
.
remove
(
cs
[
destindex
])
cs
.
remove
(
cs
[
destindex
])
cs
.
remove
(
cs
[
destindex
])
firstlook
=
0
continue
firstlook
=
1
i
=
i
+
1
def
removeconstjump
(
co
):
cs
=
co
.
co_code
cc
=
co
.
co_consts
i
=
0
while
i
<
len
(
cs
):
op
=
cs
[
i
]
if
op
.
__class__
in
CONDJUMP
and
cs
[
i
-
1
].
__class__
==
LOAD_CONST
:
if
(
op
.
__class__
==
JUMP_IF_FALSE
and
cc
[
cs
[
i
-
1
].
arg
])
or
\
(
op
.
__class__
==
JUMP_IF_TRUE
and
not
cc
[
cs
[
i
-
1
].
arg
]):
cs
.
remove
(
cs
[
i
-
1
])
cs
.
remove
(
cs
[
i
-
1
])
cs
.
remove
(
cs
[
i
-
1
])
i
=
i
-
2
else
:
cs
.
remove
(
cs
[
i
-
1
])
cs
.
remove
(
cs
[
i
])
newop
=
JUMP_FORWARD
()
newop
.
label
.
op
=
cs
[
cs
.
index
(
op
.
label
.
op
)
+
1
]
cs
[
i
-
1
]
=
newop
i
=
i
-
1
i
=
i
+
1
def
eliminateUnusedNames
(
code
):
used_names
=
{}
for
op
in
code
.
co_code
:
if
op
.
has_name
():
if
hasattr
(
op
,
"arg"
):
arg
=
op
.
arg
else
:
arg
=
op
.
arg
=
code
.
name_index
(
op
.
name
)
used_names
[
arg
]
=
1
used_names
=
used_names
.
keys
()
used_names
.
sort
()
name_mapping
=
{}
for
i
in
range
(
len
(
used_names
)):
name_mapping
[
used_names
[
i
]]
=
i
newnames
=
[]
for
i
in
range
(
len
(
code
.
co_names
)):
if
i
in
used_names
:
newnames
.
append
(
code
.
co_names
[
i
])
code
.
co_names
=
newnames
for
op
in
code
.
co_code
:
if
op
.
has_name
():
op
.
arg
=
name_mapping
[
op
.
arg
]
def
eliminateUnusedLocals
(
code
):
used_names
=
{}
for
op
in
code
.
co_code
:
if
op
.
has_local
():
if
hasattr
(
op
,
"arg"
):
arg
=
op
.
arg
else
:
arg
=
op
.
arg
=
code
.
local_index
(
op
.
name
)
used_names
[
arg
]
=
1
used_names
=
used_names
.
keys
()
used_names
.
sort
()
name_mapping
=
{}
for
i
in
range
(
len
(
used_names
)):
name_mapping
[
used_names
[
i
]]
=
i
newnames
=
[]
for
i
in
range
(
len
(
code
.
co_varnames
)):
if
i
in
used_names
:
newnames
.
append
(
code
.
co_varnames
[
i
])
code
.
co_varnames
=
newnames
for
op
in
code
.
co_code
:
if
op
.
has_local
():
op
.
arg
=
name_mapping
[
op
.
arg
]
lib/python/Products/PythonScripts/zbytecodehacks/tailr.py
0 → 100755
View file @
6429477d
from
code_editor
import
Function
from
find_function_call
import
find_function_call
from
ops
import
*
def
make_tail_recursive
(
func
):
func
=
Function
(
func
)
code
=
func
.
func_code
cs
=
code
.
co_code
index
=
0
while
1
:
stack
=
find_function_call
(
func
,
func
.
func_name
,
startindex
=
index
)
if
stack
is
None
:
break
index
=
cs
.
index
(
stack
[
-
1
])
if
cs
[
index
+
1
].
__class__
is
RETURN_VALUE
:
cs
.
remove
(
stack
[
0
])
newop
=
JUMP_ABSOLUTE
()
cs
[
index
-
1
:
index
]
=
[
newop
]
newop
.
label
.
op
=
cs
[
0
]
del
stack
[
0
],
stack
[
-
1
]
nlocals
=
len
(
code
.
co_varnames
)
code
.
co_varnames
=
code
.
co_varnames
+
code
.
co_varnames
for
op
in
stack
:
cs
.
insert
(
cs
.
index
(
op
)
+
1
,
STORE_FAST
(
stack
.
index
(
op
)
+
nlocals
))
iindex
=
cs
.
index
(
newop
)
for
i
in
range
(
len
(
stack
)):
cs
.
insert
(
iindex
,
STORE_FAST
(
i
))
cs
.
insert
(
iindex
,
LOAD_FAST
(
i
+
nlocals
))
index
=
iindex
return
func
.
make_function
()
def
_facr
(
n
,
c
,
p
):
if
c
<=
n
:
return
_facr
(
n
,
c
+
1
,
c
*
p
)
return
p
def
facr
(
n
,
_facr
=
_facr
):
return
_facr
(
n
,
1
,
1
l
)
_factr
=
make_tail_recursive
(
_facr
)
def
factr
(
n
,
_factr
=
_factr
):
return
_factr
(
n
,
1
,
1
l
)
def
faci
(
n
):
p
=
1
l
;
c
=
1
;
while
c
<=
n
:
p
=
c
*
p
c
=
c
+
1
return
p
import
time
def
suite
(
n
,
c
=
10
,
T
=
time
.
time
):
r
=
[
0
,
0
,
0
]
for
i
in
range
(
c
):
t
=
T
();
facr
(
n
);
r
[
0
]
=
T
()
-
t
+
r
[
0
]
t
=
T
();
factr
(
n
);
r
[
1
]
=
T
()
-
t
+
r
[
1
]
t
=
T
();
faci
(
n
);
r
[
2
]
=
T
()
-
t
+
r
[
2
]
print
" recursive: 1.000000000000 (arbitrarily)"
print
"tail recursive:"
,
r
[
1
]
/
r
[
0
]
print
" iterative:"
,
r
[
2
]
/
r
[
0
]
lib/python/Products/PythonScripts/zbytecodehacks/version
0 → 100755
View file @
6429477d
0.52z
lib/python/Products/PythonScripts/zbytecodehacks/xapply.py
0 → 100755
View file @
6429477d
"""
\
xapply
Inspired by Don Beaudry's functor module.
xapply exports one public function, the eponymous xapply. xapply can
be thought of as `lazy apply' or `partial argument resolution'.
It takes a function and part of it's argument list, and returns a
function with the first parameters filled in. An example:
def f(x,y):
return x+y
add1 = xapply(f,1)
add1(2) => 3
This xapply is not yet as general as that from the functor module, but
the functions return are as fast as normal function, i.e. twice as
fast as functors.
This may be generalised at some point in the future.
"""
import
new
,
string
,
re
,
types
from
ops
import
LOAD_FAST
,
LOAD_CONST
from
code_editor
import
Function
,
InstanceMethod
def
xapply_munge
(
code
,
args
,
except0
=
0
):
nconsts
=
len
(
code
.
co_consts
)
nvars
=
len
(
args
)
code
.
co_consts
.
extend
(
list
(
args
))
if
except0
:
var2constlim
=
nvars
+
1
var2constoff
=
nconsts
-
1
else
:
var2constlim
=
nvars
var2constoff
=
nconsts
cs
=
code
.
co_code
for
i
in
range
(
len
(
cs
)):
op
=
cs
[
i
]
if
op
.
__class__
is
LOAD_FAST
:
if
op
.
arg
==
0
and
except0
:
continue
if
op
.
arg
<
var2constlim
:
cs
[
i
]
=
LOAD_CONST
(
op
.
arg
+
var2constoff
)
else
:
op
.
arg
=
op
.
arg
-
nvars
code
.
co_varnames
=
code
.
co_varnames
[
nvars
:]
code
.
co_argcount
=
code
.
co_argcount
-
nvars
def
xapply_func
(
func
,
args
):
f
=
Function
(
func
)
xapply_munge
(
f
.
func_code
,
args
,
0
)
return
f
.
make_function
()
def
xapply_meth
(
meth
,
args
):
im
=
InstanceMethod
(
meth
)
xapply_munge
(
im
.
im_func
.
func_code
,
args
,
1
)
return
im
.
make_instance_method
()
def
xapply
(
callable
,
*
args
):
""" xapply(callable,arg1,arg2,...) -> callable
if
f=xapply(callable,arg1,arg2,...,argn)
then
f(arg<n+1>,....argm)
is equivalent to
callable(arg1,...,argn,arg<n+1>,..argm)
callable currently must be a function or instance method, and keyword
arguments are currently not allowed.
"""
callable_type
=
type
(
callable
)
if
callable_type
is
types
.
FunctionType
:
return
xapply_func
(
callable
,
args
)
elif
callable_type
is
types
.
UnboundMethodType
:
return
xapply_meth
(
callable
,
args
)
else
:
raise
"nope"
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment