Commit 3d88647a authored by Hanno Schlichting's avatar Hanno Schlichting

Remove ZClasses from the main code tree

parent 9b2ca2d2
Support for Zope 2.7 databases
==============================
Let's make sure we can load old ZClasses:
>>> import os
>>> from ZODB.FileStorage import FileStorage
>>> sname = os.path.join(os.path.dirname(__file__), '27.fs')
>>> s = FileStorage(sname, read_only=True)
>>> from ZODB.DB import DB
>>> db = DB(s)
>>> from Zope2.ClassFactory import ClassFactory
>>> db.classFactory = ClassFactory
>>> conn = db.open()
>>> app = conn.root()['Application']
>>> ac = app.ac
>>> ac.eek()
'xxx'
>>> ac.y = 2
>>> ac.eek()
'xx'
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Basic Item class and class manager
"""
from Acquisition import Acquired
from App.special_dtml import DTMLFile
from OFS.Image import Image
from OFS.PropertySheets import PropertySheet
from OFS.PropertySheets import View
from zExceptions import BadRequest
class ZClassBasicSheet(PropertySheet, View):
"""Provide management view for item classes
"""
_getZClass = Acquired
manage = DTMLFile('dtml/itemProp', globals())
def manage_edit(self, meta_type='', icon='', file='',
class_id=None, title=None,
selected=(),
REQUEST=None):
"""Set basic item properties.
"""
if meta_type: self.setClassAttr('meta_type', meta_type)
if file and (type(file) is type('') or file.filename):
__traceback_info__=file
image=self.getClassAttr('ziconImage', None)
if image is None:
self.setClassAttr('ziconImage',
Image('ziconImage','',file))
else:
image.manage_upload(file)
if (not icon) and REQUEST:
icon=(REQUEST['URL3'][len(REQUEST['BASE1'])+1:]
+'/ziconImage')
self.setClassAttr('icon', icon)
if title is not None:
self._getZClass().title=title
if class_id is not None and class_id != self.class_id():
self.changeClassId(class_id)
if REQUEST is not None:
return self.manage(
self, REQUEST,
manage_tabs_message='Basic properties changed')
def classMetaType(self): return self.getClassAttr('meta_type','')
def classIcon(self): return self.getClassAttr('icon','')
def show_class_id(self): return True
def class_id(self):
return (self.getClassAttr('__module__','') or '')[1:]
def zClassTitle(self): return self._getZClass().title
class ZClassViewsSheet(PropertySheet, View):
"""Provide an options management view
"""
def data(self):
return self.getClassAttr('manage_options',(),1)
manage = DTMLFile('dtml/views', globals())
def manage_edit(self, actions=[], helps=[], REQUEST=None):
"Change view actions"
options=self.data()
changed=0
if len(actions)!=len(options):
raise BadRequest, 'wrong number of actions'
for i in range(len(actions)):
if options[i]['action'] != actions[i]:
options[i]['action'] = actions[i]
changed=1
if options[i].get('help') != (self.zclass_productid(), helps[i]):
if helps[i]:
options[i]['help'] = (self.zclass_productid(), helps[i])
changed=1
elif options[i].has_key('help'):
del options[i]['help']
changed=1
if changed:
self.setClassAttr('manage_options', options)
message='The changes were saved.'
else:
message='No changes were required.'
if REQUEST is not None:
return self.manage(
self, REQUEST, manage_tabs_message=message)
def manage_delete(self, selected=[], REQUEST=None):
"Delete one or more views"
options=self.data()
newoptions=filter(
lambda d, selected=selected:
d['label'] not in selected,
options)
if len(options) != len(newoptions):
self.setClassAttr('manage_options', tuple(newoptions))
message='Views deleted'
else:
message='No views were selected for deletion'
if REQUEST is not None:
return self.manage(
self, REQUEST, manage_tabs_message=message)
def zclass_productid(self):
# find the name of the enclosing Product
obj=self
while hasattr(obj, 'aq_parent'):
obj=obj.aq_parent
try:
if obj.meta_type=='Product':
return obj.id
except:
pass
def manage_add(self, label, action, help, REQUEST=None):
"Add a view"
options=self.data()
for option in options:
if option['label']==label:
raise BadRequest, (
'Please provide a <strong>new</strong> label.'
)
if help:
t=({'label': label, 'action': action,
'help': (self.zclass_productid(), help)},)
else:
t=({'label': label, 'action': action},)
self.setClassAttr('manage_options', tuple(options) + t)
if REQUEST is not None:
return self.manage(
self, REQUEST,
manage_tabs_message='View %s has been added' % label)
def manage_first(self, selected=[], REQUEST=None):
"Make some views first"
options=self.data()
if not selected:
message="No views were selected to be made first."
elif len(selected)==len(options):
message="Making all views first has no effect."
else:
options=self.data()
options=tuple(
filter(lambda option, selected=selected:
option['label'] in selected,
options)
+
filter(lambda option, selected=selected:
option['label'] not in selected,
options)
)
self.setClassAttr('manage_options', options)
message="Views were rearranged as requested."
if REQUEST is not None:
return self.manage(
self, REQUEST, manage_tabs_message=message)
class ZClassPermissionsSheet(PropertySheet, View):
"Manage class permissions"
manage = DTMLFile('dtml/classPermissions', globals())
def possible_permissions(self):
import Products
Products_permissions = getattr(Products, '__ac_permissions__', ())
r=map(
lambda p: p[0],
Products_permissions +
self.aq_acquire('_getProductRegistryData')('ac_permissions')
)
r.sort()
return r
def manage_edit(self, selected=[], REQUEST=None):
"Remove some permissions"
import Products
Products_permissions = getattr(Products, '__ac_permissions__', ())
r=[]
for p in (
Products_permissions +
self.aq_acquire('_getProductRegistryData')('ac_permissions')):
if p[0] in selected:
r.append(p)
self.setClassAttr('__ac_permissions__', tuple(r))
if REQUEST is not None:
return self.manage(self, REQUEST,
manage_tabs_message="Permissions updated")
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Basic Item class and class manager
"""
from cgi import escape
import marshal
from AccessControl.Permission import pname
from AccessControl.PermissionMapping import aqwrap
from AccessControl.PermissionMapping import PermissionMapper
from App.Factory import Factory
from App.ProductRegistry import ProductRegistryMixin
from App.special_dtml import HTMLFile
from ExtensionClass import Base
from OFS.DTMLMethod import DTMLMethod
from OFS.Folder import Folder
from OFS.PropertySheets import PropertySheet
from OFS.PropertySheets import View
from Persistence import Persistent
from Products.PythonScripts.PythonScript import PythonScript
from zExceptions import BadRequest
from zope.contenttype import guess_content_type
from ZClasses.ZClassOwner import ZClassOwner
_marker=[]
class ZClassMethodsSheet(PropertySheet,
View,
Folder,
ProductRegistryMixin,
ZClassOwner,
):
"""Manage instance methods
"""
id = 'contents'
icon = 'p_/Methods_icon'
def tpURL(self):
return 'propertysheets/methods'
######################################################################
# Hijinks to let us create factories and classes within classes.
meta_types=(
{'name': 'Z Class',
'action':'manage_addZClassForm'},
{'name': Factory.meta_type,
'action': 'manage_addPrincipiaFactoryForm'
},
{'name': 'Property Sheet Interface',
'action': 'manage_addPropertyInterfaceForm'
},
)
def manage_addPrincipiaFactory(
self, id, title, object_type, initial, permission=None, REQUEST=None):
""" Add a factory.
"""
i = Factory(id, title, object_type, initial, permission)
self._setObject(id,i)
factory = self._getOb(id)
factory.initializePermission()
if REQUEST is not None:
return self.manage_main(self,REQUEST,update_menu=1)
def _getProductRegistryMetaTypes(self):
return self.getClassAttr('_zclass_method_meta_types',())
def _setProductRegistryMetaTypes(self, v):
return self.setClassAttr('_zclass_method_meta_types', v)
def _constructor_prefix_string(self, pid): return ''
######################################################################
manage_addPropertyInterfaceForm = HTMLFile(
'dtml/addPropertyInterface',
globals())
# This is to trigger alternate access management for methods:
_isBeingUsedAsAMethod_=1
def _isBeingUsedAsAMethod(self, REQUEST =None, wannaBe=0):
if REQUEST is not None and wannaBe: REQUEST.response.notFoundError()
return 0
def permissionMappingPossibleValues(self):
return self.classDefinedAndInheritedPermissions()
def meta_type(self):
return self.aq_inner.aq_parent.aq_parent.meta_type
def manage(self, REQUEST):
" "
return self.manage_main(self, REQUEST)
def manage_addDTMLMethod(self, id, title='', file='',
REQUEST=None, submit=None):
"Add a DTML Method using a management template"
if not file: file=default_dm_html
return ZClassMethodsSheet.inheritedAttribute('manage_addDTMLMethod')(
self, id, title, file, REQUEST, submit)
def _checkId(self, id, allow_dup=0,
_reserved=('propertysheets','manage_workspace')):
if id in _reserved:
raise BadRequest, 'The id, %s, is reserved' % escape(id)
if not allow_dup and self.getClassAttr(id, self) is not self:
raise BadRequest, (
'The id %s is invalid - it is already in use.' % escape(id))
ZClassMethodsSheet.inheritedAttribute('_checkId')(
self, id, 1)
return id+' '
def _setOb(self, id, object):
self.setClassAttr(id.strip(), MWp(object))
def _delOb(self, id):
self.delClassAttr(id.strip())
def _delObject(self, id, dp=1):
# Ick! This is necessary to deal with spaces. Waaa!
object=self._getOb(id)
object.manage_beforeDelete(object, self)
id=id.strip()
self._objects=tuple(filter(lambda i,n=id:
i['id'].strip() != n,
self._objects))
self._delOb(id)
def _getOb(self, id, default=_marker):
if default is _marker:
r=self.getClassAttr(id.strip())
else:
try: r=self.getClassAttr(id.strip())
except: return default
if hasattr(r, methodattr):
m=r.__dict__[methodattr]
if r.__class__ is W:
# Ugh, we need to convert an old wrapper to a new one
wrapper=getattr(m, '_permissionMapper', None)
if wrapper is None: wrapper=PermissionMapper()
for k, v in r.__dict__.items():
if k[:1]=='_' and k[-11:]=='_Permission':
setattr(wrapper, k, v)
m._permissionMapper=wrapper
mw=MWp(m)
self.setClassAttr(id.strip(), mw)
r=m
return getattr(r, 'aq_base', r).__of__(self)
def __bobo_traverse__(self, request, name):
if hasattr(self, 'aq_base'):
b=self.aq_base
if hasattr(b,name): return getattr(self, name)
try: return self[name]
except: return getattr(self, name)
def possible_permissions(self):
return self.classDefinedAndInheritedPermissions()
#
# FTP support
#
def manage_FTPstat(self,REQUEST):
"Psuedo stat used for FTP listings"
mode=0040000|0770
mtime=self.bobobase_modification_time().timeTime()
owner=group='Zope'
return marshal.dumps((mode,0,0,1,owner,group,0,mtime,mtime,mtime))
def PUT_factory( self, name, typ, body ):
"""
Hook PUT creation to make objects of the right type when
new item uploaded via FTP/WebDAV.
"""
if typ is None:
typ, enc = guess_content_type()
if typ == 'text/x-python':
return PythonScript( name )
if typ[ :4 ] == 'text':
return DTMLMethod( '', __name__=name )
return None # take the default, then
default_dm_html='''<html>
<head><title><dtml-var document_title></title></head>
<body bgcolor="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-var manage_tabs>
<P>This is the <dtml-var document_id> Document in
the <dtml-var title_and_id> Folder.</P>
</body></html>
'''
methodattr='_ZClassMethodPermissionMapperMethod_'
class MW(Base):
def __init__(self, meth): self.__dict__[methodattr]=meth
def __of__(self, parent):
m=getattr(self, methodattr)
m=self.__dict__[methodattr]
wrapper=getattr(m, '_permissionMapper', None)
if wrapper is None: wrapper=PermissionMapper()
if hasattr(m,'__of__'): return aqwrap(m, wrapper, parent)
return m
class MWp(Persistent):
def __init__(self, meth): self.__dict__[methodattr]=meth
__setstate__=__init__
def __getstate__(self):
getattr(self, methodattr)
return self.__dict__[methodattr]
def __of__(self, parent):
m=getattr(self, methodattr)
m=self.__dict__[methodattr]
wrapper=getattr(m, '_permissionMapper', None)
if wrapper is None: wrapper=PermissionMapper()
if hasattr(m,'__of__'): return aqwrap(m, wrapper, parent)
return m
# Backward compat. Waaaaa
class W(Persistent, MW):
_View_Permission='_View_Permission'
def __getattr__(self, name):
# We want to make sure that any non-explicitly set methods are
# private!
try:
# Oh this sucks
return W.inheritedAttribute('__getattr__')(self, name)
except: pass
if name[:1]=='_' and name[-11:]=="_Permission": return ''
raise AttributeError, name
def __of__(self, parent):
m=getattr(self, methodattr)
m=self.__dict__[methodattr]
if hasattr(m,'__of__'): return aqwrap(m, self, parent)
return m
def findMethodIds(klass, methodTypes=(MWp, MW, W)):
r=[]
for k, v in klass.__dict__.items():
if type(v) in methodTypes: r.append(k)
return r
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Object-manager mix-in for ZClasses
"""
from App.special_dtml import DTMLFile
from OFS.ObjectManager import ObjectManager as BaseObjectManager
from OFS.PropertySheets import PropertySheet
from OFS.PropertySheets import PropertySheets
from OFS.PropertySheets import View
class SubobjectsSheet(PropertySheet, View):
"""Provide management view for selecting sub-objects.
"""
manage = DTMLFile('dtml/subobjects', globals())
def possible_meta_types(self):
import Products
return self.aq_acquire('_product_meta_types') + Products.meta_types
def selected_meta_types(self):
return map(lambda v: v['name'], self.getClassAttr('meta_types',()))
def manage_edit(self, meta_types=(), isFolderish=None, REQUEST=None):
"Edit object management properties"
self.setClassAttr('meta_types', filter(
lambda d, m=meta_types: d['name'] in m,
self.possible_meta_types()
))
self.setClassAttr('isPrincipiaFolderish', isFolderish)
if REQUEST is not None:
return self.manage(
self, REQUEST,
manage_tabs_message='Changes were applied'
)
def isFolderish(self):
return self.getClassAttr('isPrincipiaFolderish', 0, 1)
class ZObjectManagerPropertySheets(PropertySheets):
subobjects=SubobjectsSheet('subobjects')
class ObjectManager(BaseObjectManager):
_zclass_method_meta_types=()
def all_meta_types(self):
return self.meta_types+self._zclass_method_meta_types
class ZObjectManager:
"""Mix-in for Object Management
"""
_zclass_ = ObjectManager
propertysheets=ZObjectManagerPropertySheets()
manage_options=(
{'label': 'Subobjects', 'action' :'propertysheets/subobjects/manage'},
)
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Provide management of common instance property sheets
"""
from AccessControl.Permission import pname
from AccessControl.Permissions import manage_zclasses
from AccessControl.Permissions import manage_properties
from AccessControl.Permissions import access_contents_information
from AccessControl.SecurityInfo import ClassSecurityInfo
from App.class_init import InitializeClass
from App.special_dtml import DTMLFile
from OFS.ObjectManager import ObjectManager
from OFS.PropertySheets import FixedSchema
from OFS.PropertySheets import PropertySheet
from OFS.PropertySheets import PropertySheets
from OFS.PropertySheets import View
from OFS.SimpleItem import Item
from OFS.Traversable import Traversable
from Persistence import Persistent
import transaction
class ClassCaretaker:
def __init__(self, klass): self.__dict__['_k']=klass
def __getattr__(self, name): return getattr(self._k, name)
def __setattr__(self, name, v):
klass=self._k
setattr(klass, name, v)
if not getattr(klass,'_p_changed',None) and klass._p_jar is not None:
transaction.get().register(klass)
klass._p_changed=1
def __delattr__(self, name):
klass=self._k
delattr(klass, name)
if not getattr(klass,'_p_changed',None) and klass._p_jar is not None:
transaction.get().register(klass)
klass._p_changed=1
class ZCommonSheet(PropertySheet, Item):
"Property Sheet that has properties common to all instances"
meta_type="Common Instance Property Sheet"
_properties=()
manage_options=(
{'label':'Properties', 'action':'manage',
'help':('OFSP','Properties.stx')},
{'label':'Define Permissions', 'action':'manage_security',
'help':('OFSP','Security_Define-Permissions.stx')},
)
security = ClassSecurityInfo()
security.declareObjectProtected(manage_zclasses)
security.declareProtected(manage_zclasses, 'manage')
def __init__(self, id, title):
self.id=id
self.title=title
self._md={}
def manage_afterAdd(self,item,container):
if item is not self: return
if self._properties:
raise ValueError, (
'Non-empty propertysheets cannot currently be '
'added (or copied).<p>')
def v_self(self):
klass=self.aq_inner.aq_parent.aq_parent.aq_parent._zclass_
return ClassCaretaker(klass)
def p_self(self): return self
def _view_widget_for_type(self, t, id):
if t not in ('lines', 'tokens'):
return '<dtml-var %s>' % id
return """
<dtml-in %s>
<dtml-var sequence-item>
</dtml-in %s>
""" % (id, id)
def manage_createView(self, id, title='', ps_view_type=None, REQUEST=None):
"""Create a view of a property sheet
"""
if ps_view_type == 'Edit':
return self.manage_createEditor(id, title, REQUEST)
r=['<dtml-var standard_html_header>',
'<table>']
a=r.append
for p in self.propertyMap():
pid=p['id']
pid=pid[:1].upper()+pid[1:]
a(' <tr><th align=left valign=top>%s</th>' % pid)
a(' <td align=left valign=top>%s</td>' %
self._view_widget_for_type(p['type'], p['id'])
)
a(' </tr>')
a('</table>')
a('<dtml-var standard_html_footer>')
r='\n'.join(r)
self.aq_parent.aq_parent.methods.manage_addDTMLMethod(id, title, r)
if REQUEST is not None:
REQUEST['RESPONSE'].redirect(REQUEST['URL3']+'/methods/manage')
def _edit_widget_for_type(self, t, id, p):
if t in ('int', 'long', 'float', 'date', 'string'):
if t=='string': q=' html_quote'
else: q=''
return ('''
<input name="%s:%s" size="35"
value="<dtml-var %s%s>">'''
% (id, t, id, q)
)
if t=='boolean':
return ('''
<input type="checkbox" name="%s:boolean" size="35"
<dtml-if %s>CHECKED</dtml-if>>'''
% (id, id)
)
if t=='tokens':
return ('''
<input type="text" name="%s:tokens" size="35"
value="<dtml-in %s><dtml-var sequence-item> </dtml-in>">'''
% (id, id)
)
if t=='text':
return ('''
<textarea name="%s:text" rows="6" cols="35"><dtml-var %s
></textarea>'''
% (id, id)
)
if t=='lines':
return ('''
<textarea name="%s:lines" rows="6" cols="35"><dtml-in %s
><dtml-var sequence-item>\n</dtml-in></textarea>'''
% (id, id)
)
if t=='selection':
return ('''
<dtml-if "_.has_key('%(id)s')">
<select name="%(id)s">
<dtml-in "_.string.split('%(select_variable)s')">
<option
<dtml-if "_['sequence-item']=='%(id)s'">
SELECTED</dtml-if>
><dtml-var sequence-item></option>
</dtml-in>
</select>
<dtml-else>
No value for %(id)s
</dtml-if>'''
% p
)
return ''
def manage_beforeDelete(self, item, container):
if self is item:
for d in self._properties:
self.delClassAttr(d['id'])
def manage_createEditor(self, id, title='', REQUEST=None):
"""Create an edit interface for a property sheet
"""
r=['<html><head><title><dtml-var title_or_id></title></head>',
'<body bgcolor="#FFFFFF" link="#000099" vlink="#555555">',
'<dtml-var manage_tabs>',
'<form action="propertysheets/%s/manage_editProperties"><table>'
% self.id]
a=r.append
for p in self.propertyMap():
a(' <tr><th align=left valign=top>%s</th>' % p['id'])
a(' <td align=left valign=top>%s</td>' %
self._edit_widget_for_type(p['type'], p['id'], p)
)
a(' </tr>')
a(' <tr><td colspan=2>')
a(' <input type=submit value=" Change ">')
a(' <input type=reset value=" Reset ">')
a(' </td></tr>')
a('</table></form>')
a('</body></html>')
r='\n'.join(r)
self.aq_parent.aq_parent.methods.manage_addDTMLMethod(id, title, r)
if REQUEST is not None:
REQUEST['RESPONSE'].redirect(REQUEST['URL3']+'/methods/manage')
def permissionMappingPossibleValues(self):
return self.classDefinedAndInheritedPermissions()
manage_security = DTMLFile('AccessControl/dtml/methodAccess')
def manage_getPermissionMapping(self):
ips=self.getClassAttr('propertysheets')
ips=getattr(ips, self.id)
# ugh
perms={}
for p in self.classDefinedAndInheritedPermissions():
perms[pname(p)]=p
r=[]
for p in property_sheet_permissions:
v=getattr(ips, pname(p))
r.append(
{'permission_name': p,
'class_permission': perms.get(v,'')
})
return r
def manage_setPermissionMapping(self, permission_names=[],
class_permissions=[],
REQUEST=None):
"Change property sheet permissions"
ips=self.getClassAttr('propertysheets')
ips=getattr(ips, self.id)
perms=self.classDefinedAndInheritedPermissions()
for i in range(len(permission_names)):
name=permission_names[i]
p=class_permissions[i]
if p and (p not in perms):
__traceback_info__=perms, p, i
raise ValueError, 'Invalid class permission'
if name not in property_sheet_permissions: continue
setattr(ips, pname(name), pname(p))
if REQUEST is not None:
return self.manage_security(
self, REQUEST,
manage_tabs_message='The permission mapping has been updated')
InitializeClass(ZCommonSheet)
property_sheet_permissions=(
# 'Access contents information',
'Manage properties',
)
class ZInstanceSheet(FixedSchema, View):
"Waaa this is too hard"
security = ClassSecurityInfo()
security.declareObjectProtected(access_contents_information)
security.declareProtected(access_contents_information, 'hasProperty')
security.declareProtected(access_contents_information, 'propertyIds')
security.declareProtected(access_contents_information, 'propertyValues')
security.declareProtected(access_contents_information, 'propertyItems')
security.declareProtected(access_contents_information, 'propertyMap')
security.declareProtected(manage_properties, 'manage')
security.declareProtected(manage_properties, 'manage_addProperty')
security.declareProtected(manage_properties, 'manage_editProperties')
security.declareProtected(manage_properties, 'manage_delProperties')
security.declareProtected(manage_properties, 'manage_changeProperties')
_Manage_properties_Permission='_Manage_properties_Permission'
_Access_contents_information_Permission='_View_Permission'
def v_self(self):
return self.aq_inner.aq_parent.aq_parent
InitializeClass(ZInstanceSheet)
def rclass(klass):
if not getattr(klass, '_p_changed', 0) and klass._p_jar is not None:
transaction.get().register(klass)
klass._p_changed=1
class ZInstanceSheetsSheet(Traversable, View, ObjectManager):
"Manage common property sheets"
# Note that we need to make sure we add and remove
# instance sheets.
id='common'
isPrincipiaFolderish=1
icon="p_/Propertysheets_icon"
dontAllowCopyAndPaste=1
def tpURL(self): return 'propertysheets/common'
def _setOb(self, id, value):
setattr(self, id, value)
pc=self.aq_inner.aq_parent.aq_parent._zclass_propertysheets_class
setattr(pc,id,ZInstanceSheet(id,value))
pc.__propset_attrs__=tuple(map(lambda o: o['id'], self._objects))
rclass(pc)
def _delOb(self, id):
delattr(self, id)
pc=self.aq_inner.aq_parent.aq_parent._zclass_propertysheets_class
try: delattr(pc,id)
except: pass
pc.__propset_attrs__=tuple(map(lambda o: o['id'], self._objects))
rclass(pc)
meta_types=({'name': ZCommonSheet.meta_type,
'action': 'manage_addCommonSheetForm',
},)
def all_meta_types(self): return self.meta_types
manage = DTMLFile('OFS/dtml/main', management_view='Property Sheets')
manage_main = manage
manage_main._setName('manage_main')
manage_addCommonSheetForm = DTMLFile('dtml/addCommonSheet', globals())
def manage_addCommonSheet(self, id, title, REQUEST=None):
"Add a property sheet"
o=ZCommonSheet(id, title)
self._setObject(id, o)
if REQUEST is not None:
return self.manage(self, REQUEST)
def klass_sequence(klass,attr,result=None):
if result is None: result={}
if hasattr(klass,attr):
for i in getattr(klass,attr): result[i]=1
for klass in klass.__bases__:
klass_sequence(klass, attr, result)
return result
class ZInstanceSheets(PropertySheets, Persistent):
" "
__propset_attrs__=()
_implements_the_notional_subclassable_propertysheet_class_interface=1
def __propsets__(self):
propsets=ZInstanceSheets.inheritedAttribute('__propsets__')(self)
r=[]
for id in klass_sequence(self.__class__,'__propset_attrs__').keys():
r.append(getattr(self, id))
return propsets+tuple(r)
InitializeClass(ZInstanceSheets)
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Zope Classes
"""
import marshal
import re
from AccessControl.Permissions import create_class_instances
from AccessControl.Role import gather_permissions
from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import aq_base
from App.class_init import InitializeClass
from App.FactoryDispatcher import FactoryDispatcher
from App.ImageFile import ImageFile
from App.special_dtml import DTMLFile
from ComputedAttribute import ComputedAttribute
from ExtensionClass import Base
from OFS.SimpleItem import SimpleItem
from OFS.PropertySheets import PropertySheets
from Persistence import Persistent
from webdav.Collection import Collection
from zExceptions import BadRequest
from zExceptions import Redirect
from ZPublisher.mapply import mapply
import transaction
from ZClasses._pmc import ZClassPersistentMetaClass
from ZClasses.Method import findMethodIds
from ZClasses.Method import ZClassMethodsSheet
from ZClasses.Basic import ZClassViewsSheet
from ZClasses.Basic import ZClassBasicSheet
from ZClasses.Basic import ZClassPermissionsSheet
from ZClasses.Property import ZInstanceSheets
from ZClasses.Property import ZInstanceSheetsSheet
import Products
if not hasattr(Products, 'meta_types'):
Products.meta_types=()
if not hasattr(Products, 'meta_classes'):
Products.meta_classes={}
Products.meta_class_info={}
def createZClassForBase( base_class, pack, nice_name=None, meta_type=None ):
"""
* Create a ZClass for 'base_class' in 'pack' (before a ProductContext
is available). 'pack' may be either the module which is to
contain the ZClass or its 'globals()'. If 'nice_name' is
passed, use it as the name for the created class, and create
the "ugly" '_ZClass_for_...' name as an alias; otherwise,
just use the "ugly" name.
* Register the ZClass under its meta_type in the Products registries.
"""
d = {}
zname = '_ZClass_for_' + base_class.__name__
if nice_name is None:
nice_name = zname
exec 'class %s: pass' % nice_name in d
Z = d[nice_name]
Z.propertysheets = PropertySheets()
Z._zclass_ = base_class
Z.manage_options = ()
try:
Z.__module__ = pack.__name__
setattr( pack, nice_name, Z )
setattr( pack, zname, Z )
except AttributeError: # we might be passed 'globals()'
Z.__module__ = pack[ '__name__' ]
pack[ nice_name ] = Z
pack[ zname ] = Z
if meta_type is None:
if hasattr(base_class, 'meta_type'): meta_type=base_class.meta_type
else: meta_type=base_class.__name__
base_module = base_class.__module__
base_name = base_class.__name__
key = "%s/%s" % (base_module, base_name)
if base_module[:9] == 'Products.':
base_module = base_module.split('.' )[1]
else:
base_module = base_module.split('.' )[0]
info="%s: %s" % ( base_module, base_name )
Products.meta_class_info[key] = info # meta_type
Products.meta_classes[key] = Z
return Z
from OFS.misc_ import p_
p_.ZClass_Icon = ImageFile('class.gif', globals())
class PersistentClass(Base, Collection):
__metaclass__ = ZClassPersistentMetaClass
# We need this class to be treated as a normal global class, even
# though it is an instance of ZClassPersistentMetaClass.
# Subclasses should be stored in the database. See
# _pmc._p_DataDescr.__get__.
__global_persistent_class_not_stored_in_DB__ = True
def __class_init__(self):
pass
manage_addZClassForm = DTMLFile(
'dtml/addZClass', globals(),
default_class_='OFS.SimpleItem Item',
CreateAFactory=1,
zope_object=1)
def find_class(ob, name):
# Walk up the aq hierarchy, looking for a ZClass
# with the given name.
while 1:
if hasattr(ob, name):
return getattr(ob, name)
elif hasattr(ob, '_getOb'):
try: return ob._getOb(name)
except: pass
if hasattr(ob, 'aq_parent'):
ob=ob.aq_parent
continue
raise AttributeError, name
bad_id=re.compile('[^a-zA-Z0-9_]').search
def manage_addZClass(self, id, title='', baseclasses=[],
meta_type='', CreateAFactory=0, REQUEST=None,
zope_object=0):
"""Add a Z Class
"""
if bad_id(id) is not None:
raise BadRequest, (
'The id %s is invalid as a class name.' % id)
if not meta_type: meta_type=id
r={}
for data in self.aq_acquire('_getProductRegistryData')('zclasses'):
r['%(product)s/%(id)s' % data]=data['meta_class']
bases=[]
for b in baseclasses:
if Products.meta_classes.has_key(b):
bases.append(Products.meta_classes[b])
elif r.has_key(b):
bases.append(r[b])
else:
raise ValueError, 'Invalid class: %s' % b
Z=ZClass(id, title, bases, zope_object=zope_object)
Z._zclass_.meta_type=meta_type
self._setObject(id, Z)
if CreateAFactory and meta_type:
from Products.PythonScripts.PythonScript import PythonScript
self.manage_addDTMLMethod(
id+'_addForm',
id+' constructor input form',
addFormDefault % {'id': id, 'meta_type': meta_type},
)
constScript = PythonScript(id+'_add')
constScript.write(addDefault % {'id': id, 'title':id+' constructor'})
self._setObject(constScript.getId(), constScript)
self.manage_addPermission(
id+'_add_permission',
id+' constructor permission',
'Add %ss' % meta_type
)
self.manage_addPrincipiaFactory(
id+'_factory',
id+' factory',
meta_type,
id+'_addForm',
'Add %ss' % meta_type
)
Z=self._getOb(id)
Z.propertysheets.permissions.manage_edit(
selected=['Add %ss' % id])
Z.manage_setPermissionMapping(
permission_names=['Create class instances'],
class_permissions=['Add %ss' % meta_type]
)
if REQUEST is not None:
return self.manage_main(self,REQUEST, update_menu=1)
class Template:
_p_oid=_p_jar=__module__=None
_p_changed=0
icon=''
def PersistentClassDict(doc=None, meta_type=None):
# Build new class dict
dict={}
dict.update(Template.__dict__)
if meta_type is not None:
dict['meta_type']=dict['__doc__']=meta_type
if doc is not None:
dict['__doc__']=doc
return dict
_marker=[]
class ZClass(Base, Collection, SimpleItem):
"""Zope Class
"""
meta_type="Z Class"
icon="p_/ZClass_Icon"
instance__meta_type='instance'
instance__icon=''
__propsets__=()
isPrincipiaFolderish=1
security = ClassSecurityInfo()
security.declareObjectProtected(create_class_instances)
def __init__(self, id, title, bases, zope_object=1):
"""Build a Zope class
A Zope class is *really* a meta-class that manages an
actual extension class that is instantiated to create instances.
"""
self.id=id
self.title=title
# Set up base classes for new class, the meta class prop
# sheet and the class(/instance) prop sheet.
base_classes=[PersistentClass]
zsheets_base_classes=[PersistentClass]
isheets_base_classes=[PersistentClass]
zbases=[ZStandardSheets]
for z in bases:
base_classes.append(z._zclass_)
zbases.append(z)
try: zsheets_base_classes.append(z.propertysheets.__class__)
except AttributeError: pass
try:
psc=z._zclass_.propertysheets.__class__
if getattr(psc,
'_implements_the_notional'
'_subclassable_propertysheet'
'_class_interface',
0):
isheets_base_classes.append(psc)
except AttributeError: pass
if zope_object:
base_classes.append(SimpleItem)
zsheets_base_classes.append(ZClassSheets)
isheets_base_classes.append(ZInstanceSheets)
# Create the meta-class property sheet
sheet_id = id+'_ZPropertySheetsClass'
zsheets_class=type(PersistentClass)(
sheet_id,
tuple(zsheets_base_classes)+(Persistent,),
PersistentClassDict(sheet_id, sheet_id))
self.propertysheets=sheets=zsheets_class()
# Create the class
self._zclass_=c=type(PersistentClass)(
id, tuple(base_classes),
PersistentClassDict(title or id))
c.__ac_permissions__=()
# Copy manage options
if zope_object:
options=[]
for option in c.manage_options:
copy={}
copy.update(option)
options.append(copy)
c.manage_options=tuple(options)
# Create the class(/instance) prop sheet *class*
isheets_class=type(PersistentClass)(
id+'_PropertySheetsClass',
tuple(isheets_base_classes),
PersistentClassDict(id+' Property Sheets'))
# Record the class property sheet class in the meta-class so
# that we can manage it:
self._zclass_propertysheets_class=isheets_class
# Finally create the new classes propertysheets by instantiating the
# propertysheets class.
c.propertysheets=isheets_class()
# Save base meta-classes:
self._zbases=zbases
def cb_isCopyable(self):
pass # for now, we don't allow ZClasses to be copied.
cb_isMoveable=cb_isCopyable
def _setBasesHoldOnToYourButts(self, bases):
# Eeeek
copy=self.__class__(self.id, self.title, bases,
hasattr(self._zclass_, '_p_deactivate')
)
copy._zclass_.__dict__.update(self._zclass_.__dict__)
transaction.get().register(copy._zclass_)
self._p_jar.exchange(self._zclass_, copy._zclass_)
self._zclass_=copy._zclass_
copy._zclass_propertysheets_class.__dict__.update(
self._zclass_propertysheets_class.__dict__)
transaction.get().register(copy._zclass_propertysheets_class)
self._p_jar.exchange(self._zclass_propertysheets_class,
copy._zclass_propertysheets_class)
self._zclass_propertysheets_class=copy._zclass_propertysheets_class
if hasattr(self.propertysheets.__class__, '_p_oid'):
copy.propertysheets.__class__.__dict__.update(
self.propertysheets.__class__.__dict__)
transaction.get().register(copy.propertysheets.__class__)
self._p_jar.exchange(self.propertysheets.__class__,
copy.propertysheets.__class__)
self._zbases=copy._zbases
def _new_class_id(self):
try:
from hashlib import md5
except:
from md5 import new as md5
import base64, time
id=md5()
id.update(self.absolute_url())
id.update(str(time.time()))
id=id.digest()
id=base64.encodestring(id).strip()
return '*'+id
security.declarePrivate('changeClassId')
def changeClassId(self, newid=None):
if newid is None: newid=self._new_class_id()
self._unregister()
if newid:
if not newid[:1] == '*': newid='*'+newid
self.setClassAttr('__module__', newid)
self._register()
def _waaa_getJar(self):
# Waaa, we need our jar to register, but we may not have one yet when
# we need to register, so we'll walk our acquisition tree looking
# for one.
jar=None
while 1:
if hasattr(self, '_p_jar'):
jar=self._p_jar
if jar is not None:
return jar
if not hasattr(self, 'aq_parent'):
return jar
self=self.aq_parent
def _register(self):
# Register the global id of the managed class:
z=self._zclass_
class_id=z.__module__
if not class_id: return
jar=self._waaa_getJar()
globals=jar.root()['ZGlobals']
if globals.has_key(class_id):
raise ValueError, 'Duplicate Class Ids'
globals[class_id]=z
product=self.aq_inner.aq_parent.zclass_product_name()
# Register self as a ZClass:
self.aq_acquire('_manage_add_product_data')(
'zclasses',
product=product,
id=self.id,
meta_type=z.meta_type or '',
meta_class=aq_base(self),
)
def _unregister(self):
# Unregister the global id of the managed class:
class_id=self._zclass_.__module__
if not class_id: return
globals=self._p_jar.root()['ZGlobals']
if globals.has_key(class_id):
del globals[class_id]
product=self.aq_inner.aq_parent.zclass_product_name()
# Unregister self as a ZClass:
self.aq_acquire('_manage_remove_product_data')(
'zclasses',
product=product,
id=self.id,
)
def zclass_product_name(self):
product=self.aq_inner.aq_parent.zclass_product_name()
return "%s/%s" % (product, self.id)
def manage_afterClone(self, item):
self.setClassAttr('__module__', None)
self.propertysheets.methods.manage_afterClone(item)
def manage_afterAdd(self, item, container):
if not self._zclass_.__module__:
self.setClassAttr('__module__', self._new_class_id())
self._register()
self.propertysheets.methods.manage_afterAdd(item, container)
def manage_beforeDelete(self, item, container):
self._unregister()
self.propertysheets.methods.manage_beforeDelete(item, container)
def manage_options(self):
r=[]
d={}
have=d.has_key
for z in self._zbases:
for o in z.manage_options:
label=o['label']
if have(label): continue
d[label]=1
r.append(o)
return r
manage_options=ComputedAttribute(manage_options)
security.declareProtected(create_class_instances, 'createInObjectManager')
def createInObjectManager(self, id, REQUEST, RESPONSE=None):
"""
Create Z instance. If called with a RESPONSE,
the RESPONSE will be redirected to the management
screen of the new instance's parent Folder. Otherwise,
the instance will be returned.
"""
i = self.fromRequest(id, REQUEST)
folder=durl=None
if hasattr(self, 'Destination'):
d=self.Destination
if d.im_self.__class__ is FactoryDispatcher:
folder=d()
if folder is None: folder=self.aq_parent
if not hasattr(folder,'_setObject'):
folder=folder.aq_parent
# An object is not guarenteed to have the id we passed in.
id = i.getId()
folder._setObject(id, i)
if RESPONSE is not None:
try: durl=self.DestinationURL()
except: durl=REQUEST['URL3']
RESPONSE.redirect(durl+'/manage_workspace')
else:
return folder._getOb(id)
security.declareProtected(create_class_instances, 'index_html')
index_html=createInObjectManager
def fromRequest(self, id=None, REQUEST={}):
if self._zclass_.__init__ is object.__init__:
# there is no user defined __init__, avoid calling
# mapply then, as it would fail while trying
# to figure out the function properties
i = self._zclass_()
else:
i = mapply(self._zclass_, (), REQUEST)
if id is not None:
try:
i._setId(id)
except AttributeError:
i.id = id
return i
security.declareProtected(create_class_instances, '__call__')
def __call__(self, *args, **kw):
return apply(self._zclass_, args, kw)
def zclass_candidate_view_actions(self):
r={}
zclass=self._zclass_
# Step one, look at all of the methods.
# We can cheat (hee hee) and and look in the _zclass_
# dict for wrapped objects.
for id in findMethodIds(zclass):
r[id]=1
# OK, now lets check out the inherited views:
findActions(zclass, r)
# OK, now add our property sheets.
for id in self.propertysheets.common.objectIds():
r['propertysheets/%s/manage' % id]=1
r=r.keys()
r.sort()
return r
security.declarePrivate('getClassAttr')
def getClassAttr(self, name, default=_marker, inherit=0):
if default is _marker:
if inherit: return getattr(self._zclass_, name)
else: return self._zclass_.__dict__[name]
try:
if inherit: return getattr(self._zclass_, name)
else: return self._zclass_.__dict__[name]
except: return default
security.declarePrivate('setClassAttr')
def setClassAttr(self, name, value):
c=self._zclass_
setattr(c, name, value)
if (not c._p_changed) and (c._p_jar is not None):
transaction.get().register(c)
c._p_changed=1
security.declarePrivate('delClassAttr')
def delClassAttr(self, name):
c=self._zclass_
delattr(c, name)
if (not c._p_changed) and (c._p_jar is not None):
transaction.get().register(c)
c._p_changed=1
def classDefinedPermissions(self):
c=self._zclass_
r=[]
a=r.append
for p in c.__ac_permissions__: a(p[0])
r.sort()
return r
def classInheritedPermissions(self):
c=self._zclass_
d={}
for p in c.__ac_permissions__: d[p[0]]=None
r=[]
a=r.append
for p in gather_permissions(c, [], d): a(p[0])
r.sort()
return r
def classDefinedAndInheritedPermissions(self):
return (self.classDefinedPermissions()+
self.classInheritedPermissions())
security.declarePublic('ziconImage')
def ziconImage(self, REQUEST, RESPONSE):
"Display a class icon"
return self._zclass_.ziconImage.index_html(REQUEST, RESPONSE)
def tpValues(self):
return self.propertysheets.common, self.propertysheets.methods
def ZClassBaseClassNames(self):
r=[]
for c in self._zbases:
if hasattr(c, 'id'): r.append(c.id)
elif hasattr(c, '__name__'): r.append(c.__name__)
return r
def _getZClass(self): return self
#
# FTP support
#
def manage_FTPlist(self,REQUEST):
"Directory listing for FTP"
out=()
files=self.__dict__.items()
if not (hasattr(self,'isTopLevelPrincipiaApplicationObject') and
self.isTopLevelPrincipiaApplicationObject):
files.insert(0,('..',self.aq_parent))
for k,v in files:
try: stat=marshal.loads(v.manage_FTPstat(REQUEST))
except:
stat=None
if stat is not None:
out=out+((k,stat),)
return marshal.dumps(out)
def manage_FTPstat(self,REQUEST):
"Psuedo stat used for FTP listings"
mode=0040000|0770
mtime=self.bobobase_modification_time().timeTime()
owner=group='Zope'
return marshal.dumps((mode,0,0,1,owner,group,0,mtime,mtime,mtime))
#
# WebDAV support
#
isAnObjectManager=1
def objectValues( self, filter=None ):
"""
"""
values = [ self.propertysheets ]
if filter is not None:
if type( filter ) == type( '' ):
filter = [ filter ]
for value in values:
if not self.propertysheets.meta_type in filter:
values.remove( value )
return values
InitializeClass(ZClass)
class ZClassSheets(PropertySheets):
"Manage a collection of property sheets that provide ZClass management"
#isPrincipiaFolderish=1
#def tpValues(self): return self.methods, self.common
#def tpURL(self): return 'propertysheets'
def manage_workspace(self, URL2):
"Emulate standard interface for use with navigation"
raise Redirect, URL2+'/manage_workspace'
views = ZClassViewsSheet('views')
basic = ZClassBasicSheet('basic')
permissions = ZClassPermissionsSheet('permissions')
def __init__(self):
self.methods = ZClassMethodsSheet('methods')
self.common = ZInstanceSheetsSheet('common')
#
# FTP support
#
def manage_FTPlist(self,REQUEST):
"Directory listing for FTP"
out=()
files=self.__dict__.items()
if not (hasattr(self,'isTopLevelPrincipiaApplicationObject') and
self.isTopLevelPrincipiaApplicationObject):
files.insert(0,('..',self.aq_parent))
for k,v in files:
try: stat=marshal.loads(v.manage_FTPstat(REQUEST))
except:
stat=None
if stat is not None:
out=out+((k,stat),)
return marshal.dumps(out)
def manage_FTPstat(self,REQUEST):
"Psuedo stat used for FTP listings"
mode=0040000|0770
mtime=self.bobobase_modification_time().timeTime()
owner=group='Zope'
return marshal.dumps((mode,0,0,1,owner,group,0,mtime,mtime,mtime))
#
# WebDAV support
#
isAnObjectManager=1
def objectValues( self, filter=None ):
return [ self.methods, self.common ]
class ZObject:
manage_options=(
{'label': 'Methods', 'action' :'propertysheets/methods/manage',
'help':('OFSP','ZClass_Methods.stx')},
{'label': 'Basic', 'action' :'propertysheets/basic/manage',
'help':('OFSP','ZClass_Basic.stx')},
{'label': 'Views', 'action' :'propertysheets/views/manage',
'help':('OFSP','ZClass_Views.stx')},
{'label': 'Property Sheets', 'action' :'propertysheets/common/manage',
'help':('OFSP','ZClass_Property-Sheets.stx')},
{'label': 'Permissions',
'action' :'propertysheets/permissions/manage',
'help':('OFSP','ZClass_Permissions.stx')},
{'label': 'Define Permissions', 'action' :'manage_access',
'help':('OFSP','Security_Define-Permissions.stx')},
)
ZStandardSheets=ZObject
def findActions(klass, found):
for b in klass.__bases__:
try:
for d in b.manage_options:
found[d['action']]=1
findActions(b, found)
except: pass
addFormDefault="""<HTML>
<HEAD><TITLE>Add %(meta_type)s</TITLE></HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<H2>Add %(meta_type)s</H2>
<form action="%(id)s_add"><table>
<tr><th>Id</th>
<td><input type=text name=id></td>
</tr>
<tr><td></td><td><input type=submit value=" Add "></td></tr>
</table></form>
</body></html>
"""
addDefault="""## Script (Python) "%(id)s_add"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=redirect=1
##title=%(title)s
##
# Add a new instance of the ZClass
request = context.REQUEST
instance = container.%(id)s.createInObjectManager(request['id'], request)
# *****************************************************************
# Perform any initialization of the new instance here.
# For example, to update a property sheet named "Basic" from the
# form values, uncomment the following line of code:
# instance.propertysheets.Basic.manage_editProperties(request)
# *****************************************************************
if redirect:
# redirect to the management view of the instance's container
request.RESPONSE.redirect(instance.aq_parent.absolute_url() + '/manage_main')
else:
# If we aren't supposed to redirect (ie, we are called from a script)
# then just return the ZClass instance to the caller
return instance
"""
Basic ZClass Tests
==================
We can create ZClasses from Python, It's a bit complicated, as
ZClasses were designed mainly to be used from the web.
First, we need to install the ZClass-aware class factory in our
database:
>>> import Zope2.App.ClassFactory
>>> some_database.classFactory = Zope2.App.ClassFactory.ClassFactory
To do anything, we need a working Zope object space:
>>> conn = some_database.open()
>>> from OFS.Application import Application
>>> app = Application()
>>> conn.root()['Application'] = app
>>> from OFS.Folder import manage_addFolder
>>> manage_addFolder(app, 'temp_folder')
>>> from OFS.Application import initialize
>>> initialize(app)
>>> app.manage_addFolder('sandbox')
>>> sandbox = app.sandbox
Once we have an object space, we need to create a product to hold the ZClass:
>>> app.Control_Panel.Products.manage_addProduct('test', '')
>>> test = app.Control_Panel.Products['test']
Then we can create the ZClass in the product:
>>> test.manage_addZClass('C', zope_object=True, CreateAFactory=True)
Having created a ZClass, we can create an instance.
When setting the 'CreateAFactory' flag, a factory will be created which
can be called from the web to create a new instance of 'C'. It also places
an option for adding 'C's in the Add-menu in the ZMI.
>>> factory = test.C_factory
>>> factory.__class__
<class 'App.Factory.Factory'>
The other objects created are:
- a permission "C_add_permission" required to access the factory,
>>> test.C_add_permission.meta_type
'Zope Permission'
- an initial add-form "C_addForm" which calls
>>> test.C_addForm.meta_type
'DTML Method'
- the add-script "C_add" for creating a new 'C' instance
>>> test.C_add.meta_type
'Script (Python)'
The factory stores the name of the initial page and its permission name:
>>> factory.initial, factory.permission
('C_addForm', 'Add Cs')
We only need a simple add-script in this scenario:
>>> factory.initial = 'C_add'
>>> test.C_add.ZPythonScript_edit('',
... '##parameters=dispatcher, request\n'
... 'return container.C.createInObjectManager('
... 'request["id"], request)\n')
...
Anonymous users are usually not allowed to create new content:
add a new user...
>>> app.acl_users._addUser('admin', 'pass', 'pass', (), ())
>>> user = app.acl_users.getUser('admin').__of__(app.acl_users)
log in as user 'admin'...
>>> from AccessControl.SecurityManagement import newSecurityManager
>>> newSecurityManager(None, user)
Now simulate a browser request to add a 'C' instance with id 'z':
>>> request = {'id': 'z'}
>>> from zExceptions.unauthorized import Unauthorized
>>> try:
... sandbox.manage_addProduct['test'].C_factory.index_html(request)
... except Unauthorized:
... print 'not authorized'
not authorized
All right, allow the admin user to 'Add Cs':
>>> bool(user.has_permission('Add Cs', sandbox))
False
>>> sandbox.manage_addLocalRoles('admin', ['Admin'])
>>> sandbox.manage_permission('Add Cs', roles=['Admin'])
>>> bool(user.has_permission('Add Cs', sandbox))
True
Try again:
>>> request = {'id': 'z'}
>>> sandbox.manage_addProduct['test'].C_factory.index_html(request)
<C at /sandbox/z>
>>> app.sandbox.z
<C at /sandbox/z>
Log out:
>>> from AccessControl.SecurityManagement import noSecurityManager
>>> noSecurityManager()
From python there is a much simpler way for creating a ZClass instance:
>>> c = test.C()
>>> c._setId('c')
>>> app._setObject('c', c)
'c'
Now, ZClass instances aren't very interesting by themselves. We can
give them data by defining property sheets:
>>> test.C.propertysheets.common.manage_addCommonSheet('basic', '')
>>> test.C.propertysheets.common['basic'].manage_addProperty(
... 'x', 'hee ', 'string')
>>> app.c.x
'hee '
>>> test.C.propertysheets.common['basic'].manage_addProperty(
... 'y', 42, 'int')
>>> app.c.y
42
Of course, we can change the data:
>>> app.c.x = 'hi '
>>> app.c.y = 3
>>> app.c.x, app.c.y
('hi ', 3)
We can also add methods, such as Python scripts:
>>> test.C.propertysheets.methods.manage_addProduct[
... 'PythonScripts'].manage_addPythonScript('eek')
''
>>> test.C.propertysheets.methods['eek'].ZPythonScript_edit('',
... 'return container.x * container.y')
>>> app.c.eek()
'hi hi hi '
Let's commit our changes:
>>> import transaction
>>> transaction.commit()
We can access the class in another connection. We'll use an explicit
transaction manager so that we can use the second connection without
creating a separate thread:
>>> tm2 = transaction.TransactionManager()
>>> conn2 = some_database.open(transaction_manager=tm2)
>>> app2 = conn2.root()['Application']
>>> test2 = app2.Control_Panel.Products['test']
>>> c2 = test2.C()
>>> c2._setId('c2')
>>> app2._setObject('c2', c2)
'c2'
>>> app2.c2.x = '*'
>>> print app2.c2.x, app2.c2.y, app2.c2.eek(), '!'
* 42 ****************************************** !
>>> print app.c.x, app.c.y, app.c.eek(), '!'
hi 3 hi hi hi !
>>> tm2.commit()
Of course, we should be able to see the new object created in the
other connection:
>>> conn.sync()
>>> app.c2.eek()
'******************************************'
We can copy instances:
>>> c3 = app.c2._getCopy(app)
>>> c3 is app.c2.aq_base
False
>>> app.c3 = c3
>>> app.c3.eek()
'******************************************'
But the copies share a common class:
>>> c3.__class__ is app.c2.__class__
True
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
"""Zope Classes
"""
from App.class_init import InitializeClass
from App.special_dtml import HTMLFile
from ExtensionClass import Base
def manage_subclassableClassNames(self):
import Products
r={}
r.update(Products.meta_class_info)
for data in self.aq_acquire('_getProductRegistryData')('zclasses'):
r['%(product)s/%(id)s' % data] = '%(product)s: %(id)s' % data
r=r.items()
r.sort()
return r
class ZClassOwner(Base):
manage_addZClassForm=HTMLFile(
'dtml/addZClass', globals(),
default_class_='OFS.SimpleItem Item',
CreateAFactory=1,
zope_object=1)
def manage_addZClass(self, id, title='', baseclasses=[],
meta_type='', CreateAFactory=0,
REQUEST=None, zope_object=0):
"Add a ZClass"
from ZClasses.ZClass import manage_addZClass
return manage_addZClass(
self, id, title, baseclasses, meta_type, CreateAFactory,
REQUEST, zope_object=zope_object)
manage_subclassableClassNames=manage_subclassableClassNames
InitializeClass(ZClassOwner)
##############################################################################
#
# Copyright
#
# Copyright 1996 Digital Creations, L.C., 910 Princess Anne
# Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All
# rights reserved.
#
##############################################################################
__doc__='''Sample product initialization module
The job of this module is to provide any run-time initialization
needed by a product and to define product meta data.
This sample product publishes a folder-ish and a simple object.
$Id$'''
__version__='$Revision: 1.7 $'[11:-2]
import warnings
warnings.warn('ZClasses are deprecated, unmaintained and should no longer be used',
DeprecationWarning,
stacklevel=2)
import ZClass
import ZClassOwner
createZClassForBase = ZClass.createZClassForBase
# Names of objects added by this product:
meta_types=(
{'name': ZClass.ZClass.meta_type,
'action':'manage_addZClassForm'},
)
# Attributes (usually "methods") to be added to folders to support
# creating objects:
methods={
'manage_addZClassForm': ZClass.manage_addZClassForm,
'manage_addZClass': ZClass.manage_addZClass,
'manage_subclassableClassNames': ZClassOwner.manage_subclassableClassNames,
}
# Permission to be added to folders:
__ac_permissions__=(
# To add items:
('Add Zope Class',
('manage_addZClassForm', 'manage_addZClass',
'manage_subclassableClassNames')),
)
misc_={}
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""ZCLass Persistent Meta Class
IMPORTANT -- This module is private to ZClasses and experimetal.
It is highly subject to change and likely to move
$Id$
"""
import ExtensionClass
import ZODB.persistentclass
# See the comments in ZODB.persistentclass
class ZClassPersistentMetaClass(ExtensionClass.ExtensionClass):
# For weird reasons having to do with restrictions on built-in
# types, we can't subclass
# ZODB.persistentclass.PersistentMetaClass, so we do the next best
# thing:
for name in ('_p_jar', '_p_oid', '_p_changed', '_p_serial',
'__getnewargs__', '_p_maybeupdate', '_p_deactivate',
'_p_invalidate', '__getstate__', '_p_activate', ):
locals()[name] = ZODB.persistentclass.PersistentMetaClass.__dict__[
name]
def __new__(self, name, bases, cdict, _p_changed=False):
# _p_changed will be None if we are being loaded from the
# database, because __getnewargs__ returns an extra argument
# for _p_changed.
# The above is *not* true for old (< 2.8) ZClass code.
# Old ZClass records have all of their data in their
# arguments. This is rather fortunate. It means that
# we don't need to call __setstate__. We *do*, however, need
# to call pmc_init_of.
cdict = dict([(k, v) for (k, v) in cdict.items()
if not k.startswith('_p_')])
cdict['_p_class_dict'] = {'_p_changed': _p_changed}
result = super(ZClassPersistentMetaClass, self
).__new__(self, name, bases, cdict)
ExtensionClass.pmc_init_of(result)
return result
# copy_reg.py:_slotnames() tries to use this attribute as a cache.
# Dont allow this attribute to be written as it may cause us
# to register with the data_manager.
__slotnames__ = property(None)
def __setattr__(self, name, v):
super(ZClassPersistentMetaClass, self).__setattr__(name, v)
if not ((name.startswith('_p_') or name.startswith('_v'))):
self._p_maybeupdate(name)
def __delattr__(self, name):
super(ZClassPersistentMetaClass, self).__delattr__(name)
if not ((name.startswith('_p_') or name.startswith('_v'))):
self._p_maybeupdate(name)
def __setstate__(self, state):
try:
self.__bases__, cdict = state
except TypeError:
# Maybe an old ZClass with state == None
if state is None:
cdict = None
if cdict is not None:
cdict = dict([(k, v) for (k, v) in cdict.items()
if not k.startswith('_p_')])
_p_class_dict = self._p_class_dict
self._p_class_dict = {}
to_remove = [
k for k in self.__dict__
if ((k not in cdict)
and
(k not in ZODB.persistentclass.special_class_descrs)
and
(k != '_p_class_dict')
)]
for k in to_remove:
delattr(self, k)
try:
del cdict['__slotnames__']
except KeyError:
pass
for k, v in cdict.items():
setattr(self, k, v)
self._p_class_dict = _p_class_dict
ExtensionClass.pmc_init_of(self)
self._p_changed = False
__setstate__ = ZODB.persistentclass._p_MethodDescr(__setstate__)
Persistent Extension Classes
============================
The _pmc module provides a meta class that can be used to implement
persistent extension classes for ZClasses.
Persistent classes have the following properties:
- They cannot be turned into ghosts
- They can only contain picklable subobjects
- They don't live in regular file-system modules
Let's look at an example:
>>> def __init__(self, name):
... self.name = name
>>> def foo(self):
... return self.name, self.kind
>>> import ZClasses._pmc
>>> class C:
... __metaclass__ = ZClasses._pmc.ZClassPersistentMetaClass
... __init__ = __init__
... __module__ = '__zodb__'
... foo = foo
... kind = 'sample'
This example is obviously a bit contrived. In particular, we defined
the methods outside of the class. Why? Because all of the items in a
persistent class must be picklable. We defined the methods as global
functions to make them picklable.
Also note that we explictly set the module. Persistent classes don't
live in normal Python modules. Rather, they live in the database. We
use information in __module__ to record where in the database. When
we want to use a database, we will need to supply a custom class
factory to load instances of the class.
The class we created works a lot like other persistent objects. It
has standard standard persistent attributes:
>>> C._p_oid
>>> C._p_jar
>>> C._p_serial
>>> C._p_changed
False
Because we haven't saved the object, the jar, oid, and serial are all
None and it's not changed.
We can create and use instances of the class:
>>> c = C('first')
>>> c.foo()
('first', 'sample')
We can modify the class and none of the persistent attributes will
change because the object hasn't been saved.
>>> def bar(self):
... print 'bar', self.name
>>> C.bar = bar
>>> c.bar()
bar first
>>> C._p_oid
>>> C._p_jar
>>> C._p_serial
>>> C._p_changed
False
Now, we can store the class in a database. We're going to use an
explicit transaction manager so that we can show parallel transactions
without having to use threads.
>>> import transaction
>>> tm = transaction.TransactionManager()
>>> connection = some_database.open(transaction_manager=tm)
>>> connection.root()['C'] = C
>>> tm.commit()
Now, if we look at the persistence variables, we'll see that they have
values:
>>> C._p_oid
'\x00\x00\x00\x00\x00\x00\x00\x01'
>>> C._p_jar is not None
True
>>> C._p_serial is not None
True
>>> C._p_changed
False
Now, if we modify the class:
>>> def baz(self):
... print 'baz', self.name
>>> C.baz = baz
>>> c.baz()
baz first
We'll see that the class has changed:
>>> C._p_changed
True
If we abort the transaction:
>>> tm.abort()
Then the class will return to it's prior state:
>>> c.baz()
Traceback (most recent call last):
...
AttributeError: baz
>>> c.bar()
bar first
We can open another connection and access the class there.
>>> tm2 = transaction.TransactionManager()
>>> connection2 = some_database.open(transaction_manager=tm2)
>>> C2 = connection2.root()['C']
>>> c2 = C2('other')
>>> c2.bar()
bar other
If we make changes without commiting them:
>>> C.bar = baz
>>> c.bar()
baz first
>>> C is C2
False
Other connections are unaffected:
>>> connection2.sync()
>>> c2.bar()
bar other
Until we commit:
>>> tm.commit()
>>> connection2.sync()
>>> c2.bar()
baz other
Similarly, we don't see changes made in other connections:
>>> C2.color = 'red'
>>> tm2.commit()
>>> c.color
Traceback (most recent call last):
...
AttributeError: color
until we sync:
>>> connection.sync()
>>> c.color
'red'
Instances of Persistent Classes
-------------------------------
We can, of course, store instances of perstent classes in the
database:
>>> c.color = 'blue'
>>> connection.root()['c'] = c
>>> tm.commit()
>>> connection2.sync()
>>> connection2.root()['c'].color
'blue'
NOTE: If a non-persistent instance of a persistent class is copied,
the class may be copied as well. This is usually not the desired
result.
Persistent instances of persistent classes
------------------------------------------
Persistent instances of persistent classes are handled differently
than normal instances. When we copy a persistent instances of a
persistent class, we want to avoid copying the class.
Lets create a persistent class that subclasses Persistent:
>>> import persistent
>>> class P(persistent.Persistent, C):
... __module__ = '__zodb__'
... color = 'green'
>>> connection.root()['P'] = P
>>> tm.commit()
The persistence variables are as expected:
>>> P._p_oid
'\x00\x00\x00\x00\x00\x00\x00\x02'
>>> P._p_jar is not None
True
>>> P._p_serial is not None
True
>>> P._p_changed
False
>>> initial_serial = P._p_serial
>>> import persistent.mapping
>>> connection.root()['obs'] = persistent.mapping.PersistentMapping()
>>> p = P('p')
>>> connection.root()['obs']['p'] = p
>>> tm.commit()
The class will be unaffected:
>>> P._p_oid
'\x00\x00\x00\x00\x00\x00\x00\x02'
>>> P._p_jar is not None
True
>>> P._p_serial == initial_serial
True
>>> P._p_changed
False
You might be wondering why we didn't just stick 'p' into the root
object. We created an intermediate persistent object instead. We are
storing persistent classes in the root object. To create a ghost for a
persistent instance of a persistent class, we need to be able to be
able to access the root object and it must be loaded first. If the
instance was in the root object, we'd be unable to create it while
loading the root object.
Now, if we try to load it, we get a broken oject:
>>> connection2.sync()
>>> connection2.root()['obs']['p']
<persistent broken __zodb__.P instance '\x00\x00\x00\x00\x00\x00\x00\x04'>
because the module, "__zodb__" can't be loaded. We need to provide a
class factory that knows about this special module. Here we'll supply a
sample class factory that looks up a class name in the database root
if the module is "__zodb__". It falls back to the normal class lookup
for other modules:
>>> from ZODB.broken import find_global
>>> def classFactory(connection, modulename, globalname):
... if modulename == '__zodb__':
... return connection.root()[globalname]
... return find_global(modulename, globalname)
>>> some_database.classFactory = classFactory
Normally, the classFactory should be set before a database is opened.
We'll reopen the connections we're using. We'll assign the old
connections to a variable first to prevent getting them from the
connection pool:
>>> old = connection, connection2
>>> connection = some_database.open(transaction_manager=tm)
>>> connection2 = some_database.open(transaction_manager=tm2)
Now, we can read the object:
>>> connection2.root()['obs']['p'].color
'green'
>>> connection2.root()['obs']['p'].color = 'blue'
>>> tm2.commit()
>>> connection.sync()
>>> p = connection.root()['obs']['p']
>>> p.color
'blue'
Copying
-------
If we copy an instance via export/import, the copy and the original
share the same class:
>>> file = connection.exportFile(p._p_oid)
>>> file.seek(0)
>>> cp = connection.importFile(file)
>>> cp.color
'blue'
>>> cp is not p
True
>>> cp.__class__ is p.__class__
True
__of__
======
Extension Classes define a special method __of__. Extension classes
that define __of__ attributes are treated as read descriptors and the
__of__ method is also used as a __get__ methods.
Let's look at an example.
>>> from ExtensionClass import Base
>>> class Named(Base):
... def __init__(self, name):
... self.name = name
... def __repr__(self):
... return self.name
>>> class WithOf(Named):
... def __of__(self, parent):
... print '__of__', self, parent
... return self
>>> n = Named('n')
>>> n.w = WithOf('w')
>>> w = n.w
__of__ w n
We see that __of__ was called when we did the getattr. Now let's try a
persistent version:
>>> C = connection.root()['C']
>>> class PersistentWithOf(C, WithOf):
... pass
>>> n.w = PersistentWithOf('pw')
>>> w = n.w
__of__ pw n
(We reloaded C from the connection we were going to use.)
Now we'll save our class in the database and reload it:
>>> connection.root()['PW'] = PersistentWithOf
>>> tm.commit()
>>> connection2.sync()
>>> PW = connection2.root()['PW']
And the class loaded from the database will have the same behavior:
>>> n.w = PW('pw2')
>>> w = n.w
__of__ pw2 n
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Common Instance Property Sheet',
help_product='OFSP',
help_topic='Common-Instance-Property-Sheet_Add.stx'
)">
<FORM ACTION="manage_addCommonSheet" METHOD="POST">
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Id
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="id" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-optional">
Title
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40">
</TD>
</TR>
<TR>
<TD></TD>
<TD>
<div class="form-element">
<input class="form-element" type="submit" name="submit" value=" Add " />
</div>
</TD>
</TR>
</TABLE>
</FORM>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Icon',
)">
<p class="form-help">
Instance Icons are displayed with images in management interfaces.
Select an image file from your local computer by clicking the
<em>browse</em> button. The image you select will be uploaded
to the class for use by instances.
</p>
<p class="form-help">
The instance icon property will be set to give a path to the image.
The path will be based on the current location of this class and
will need to be adjusted if the class is moved.
</p>
<FORM ACTION="manage_addInstanceIcon" METHOD="POST"
ENCTYPE="multipart/form-data">
<TABLE CELLSPACING="2">
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Id
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="id" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-optional">
Title
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40">
</TD>
</TR>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP">
<div class="form-label">
Icon Image
</div>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="file" NAME="file" SIZE="25" VALUE="">
</TD>
</TR>
<TR>
<TD></TD>
<TD>
<div class="form-element">
<input class="form-element" type="submit" name="submit" value=" Add " />
</div>
</TD>
</TR>
</TABLE>
</FORM>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Property Sheet Interface',
)">
<form action="../common">
<table cellspacing="2">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Property Sheet
</div>
</td>
<td align="left" valign="top">
<div class="form-element">
<select name=":method">
<dtml-in "propertysheets.common.objectValues()">
<option value="&dtml-id;/manage_createView"
>&dtml-title_and_id;</option>
</dtml-in>
</select>
</div>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Type
</div>
</td>
<td align="left" valign="top">
<div class="form-element">
<select name="ps_view_type">
<option>View</option>
<option>Edit</option>
</select>
</div>
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit" value=" Add " />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add ZClass',
help_product='OFSP',
help_topic='ZClass_Add.stx'
)">
<dtml-with "_(selected=[], unselected=[], baseclasses=[], id='', title='',
meta_type='',
all=manage_subclassableClassNames(),
)">
<dtml-with REQUEST>
<dtml-with "_(
selected=_.reorder(
all,
with = baseclasses+
(REQUEST.get('manage_addZClassForm','')==' >> '
and unselected or []),
without= (REQUEST.get('manage_addZClassForm','')==' << '
and selected or [])
),
)">
<div style="border: 1pt solid red;margin-top: 1em; margin-bottom: 1em; padding: 1em;">
ZClasses are a deprecated feature and should no longer be used for new projects.
<br/>
Instead use either through-the-web scripting with Zope Page Templates,
PythonScripts etc. or write a Zope product.
</div>
<dtml-with "_(unselected=_.reorder(all, without=selected))">
<form action="&dtml-URL1;" method="get">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top" colspan="3">
<input type="text" name="id" value="&dtml-id;" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="top" colspan="3">
<input type="text" name="title" value="&dtml-title;" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Meta Type
</div>
</td>
<td align="left" valign="top" colspan="3">
<input type="text" name="meta_type" value="&dtml-meta_type;" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top" colspan="3">
<div class="form-label">
<input type="checkbox" name="CreateAFactory:int" value="1"<dtml-if
CreateAFactory> checked</dtml-if>>
Create constructor objects?
</div>
</td>
</tr>
</table>
<br />
<table cellspacing="0" cellpadding="2" border="0">
<tr class="list-header">
<td align="left" valign="top" colspan="3">
<div class="form-label">
Base Classes
</div>
</td>
</tr>
<tr>
<td align="left" valign="top">
<!-- start -->
<div class="form-element">
<span class="form-label">Unselected</span>
<br />
<SELECT NAME="unselected:list" size=9 multiple>
<dtml-in unselected>
<OPTION VALUE="&dtml-sequence-key;"
>&dtml-sequence-item;</OPTION>
</dtml-in>
</SELECT>
</div>
<!-- end -->
</td>
<td align="left" valign="middle">
<div class="form-element">
<dtml-in selected>
<input type=hidden name="baseclasses:list" value="&dtml-sequence-key;"></dtml-in>
<INPUT class="form-element" TYPE="SUBMIT"
NAME="manage_addZClassForm:method" VALUE=" >> ">
<BR />
<INPUT class="form-element" TYPE="SUBMIT"
NAME="manage_addZClassForm:method" VALUE=" << ">
</div>
</td>
<td align="left" valign="top">
<!-- start -->
<div class="form-element">
<span class="form-label">Selected</span>
<br />
<SELECT NAME="selected:list" size=9 multiple>
<dtml-in selected>
<OPTION VALUE="&dtml-sequence-key;"
>&dtml-sequence-item;</OPTION>
</dtml-in>
</SELECT>
</div>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="3">
<div class="form-label">
<INPUT TYPE="CHECKBOX" NAME="zope_object:int" VALUE="1"<dtml-if
zope_object> CHECKED</dtml-if>>
Include standard Zope persistent object base classes?
</div>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="3">
<div class="form-element">
<input class="form-element" type="submit" name="manage_addZClass:method"
value=" Add " />
<INPUT TYPE="HIDDEN" NAME="zope_object:default:int" VALUE="0" />
<INPUT TYPE="HIDDEN" NAME="CreateAFactory:default:int" VALUE="0" />
</div>
</td>
</tr>
</table>
</form>
</dtml-with>
</dtml-with>
</dtml-with>
</dtml-with>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-with "_(management_view='Permissions')">
<dtml-if manage_tabs><dtml-var manage_tabs></dtml-if>
</dtml-with>
<p class="form-help">
Use this view to select permissions used by this class.
When setting permissions for individual methods or property sheets,
you will be able to select from class permissions and inherited
permissions.
</p>
<form action="manage_edit">
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Class Permissions
</div>
</td>
<td align="left" valign="top">
<div class="form-label">
Inherited Permissions
</div>
</td>
</tr>
<tr>
<tr>
<td align="left" valign="top">
<div class="form-element">
<dtml-let selected=classDefinedPermissions>
<select name="selected:list" multiple size=9>
<dtml-in possible_permissions>
<option
<dtml-if "_['sequence-item'] in selected">selected</dtml-if>
>&dtml-sequence-item;</option>
</dtml-in>
</select>
</dtml-let>
</div>
</td>
<td align="left" valign="top">
<div class="form-text">
<dtml-in classInheritedPermissions sort>
&dtml-sequence-item;<br />
</dtml-in>
</div>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value="Save Changes" />
</div>
</td>
<td align="left" valign="top">
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML lang="en">
<HEAD>
<TITLE>Contents</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" LINK="#000099" VLINK="#555555">
<dtml-var manage_tabs>
<P>
<FORM ACTION="." METHOD="POST">
<dtml-if objectItems>
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="2">
<dtml-in objectItems sort>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="16">
<INPUT TYPE="CHECKBOX" NAME="ids:list" VALUE="&dtml-sequence-key;">
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<dtml-if icon>
<A HREF="&dtml.url_quote-sequence-key;/manage_workspace">
<IMG SRC="&dtml.url_quote-SCRIPT_NAME;/&dtml.url_quote-icon;"
ALT="[&dtml-meta_type;]" BORDER="0"></A>
</dtml-if icon>
</TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<A HREF="&dtml.url_quote-sequence-key;/manage_workspace">
<dtml-if "_['sequence-key'][:10]=='instance__'">
<dtml-var "_['sequence-key'][10:]" html_quote>
<dtml-else >&dtml-sequence-key;
</dtml-if>
<dtml-if title>(&dtml-title;)</dtml-if>
</A>
<dtml-if locked_in_version>
<dtml-if modified_in_version>
<IMG SRC="&dtml.url_quote-SCRIPT_NAME;/p_/locked"
ALT="This item has been modified in this version">
<dtml-else>
<IMG SRC="&dtml.url_quote-SCRIPT_NAME;/p_/lockedo"
ALT="This item has been modified in another version">
</dtml-if>
</dtml-if>
</TD>
</TR>
</dtml-in>
</TABLE>
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING=2>
<TR>
<TD ALIGN="LEFT" VALIGN="TOP" WIDTH="16"></TD>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="SUBMIT" NAME="manage_renameForm:method" VALUE="Rename">
<INPUT TYPE="SUBMIT" NAME="manage_cutObjects:method" VALUE="Cut">
<INPUT TYPE="SUBMIT" NAME="manage_copyObjects:method" VALUE="Copy">
<dtml-if cb_dataValid>
<INPUT TYPE="SUBMIT" NAME="manage_pasteObjects:method" VALUE="Paste">
</dtml-if>
<INPUT TYPE="SUBMIT" NAME="manage_delObjects:method" VALUE="Delete">
<INPUT TYPE="SUBMIT" NAME="manage_importExportForm:method" VALUE="Export...">
</TD>
</TR>
</TABLE>
<dtml-else>
<TABLE BORDER="0" CELLSPACING="0" CELLPADDING="2">
<TR>
<TD>
There are currently no items in <EM>&dtml-title_or_id;</EM>
<P>
<dtml-if cb_dataValid>
<INPUT TYPE="SUBMIT" NAME="manage_pasteObjects:method" VALUE="Paste">
</dtml-if>
</TD>
</TABLE>
</dtml-if>
</FORM>
<TABLE>
<TR>
<TD VALIGN="TOP">
To add a new item, select an item type and click &quot;Add&quot;.
</TD>
<TD VALIGN="TOP">
<FORM ACTION="." METHOD="GET">
<SELECT NAME=":method">
<dtml-in all_meta_types mapping>
<OPTION value="&dtml-action;">&dtml-name;
</dtml-in all_meta_types>
</SELECT><BR>
<INPUT TYPE="SUBMIT" VALUE=" Add ">
</FORM>
</TD>
</TR>
</TABLE>
<dtml-if update_menu>
<SCRIPT LANGUAGE="javascript">
<!--
window.parent.update_menu();
//-->
</SCRIPT>
</dtml-if>
</BODY>
</HTML>
<dtml-var manage_page_header>
<dtml-with "_(management_view='Basic')">
<dtml-var manage_tabs>
</dtml-with>
<p class="form-help">
Instance Icons are displayed with images in management interfaces.
Select an image file from your local computer by clicking the
<em>Browse</em> button. The image you select will be uploaded
to the class for use by instances.
</p>
<p class="form-help">
The instance icon property will be set to give a path to the image.
The path will be based on the current location of this class and
will need to be adjusted if the class is moved.
</p>
<FORM ACTION="manage_edit" METHOD="POST"
ENCTYPE="multipart/form-data">
<TABLE CELLSPACING="2">
<TR>
<td align="left" valign="top">
<div class="form-label">
Base Classes
</div>
</td>
<TD ALIGN="LEFT" VALIGN="TOP"><dtml-var "_.string.join(ZClassBaseClassNames(), ', ')" html_quote>
</TD>
</TR>
<TR>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="title" SIZE="40"
value="&dtml-zClassTitle;">
</TD>
</TR>
<TR>
<td align="left" valign="top">
<div class="form-label">
Meta Type
</div>
</td>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="meta_type" SIZE="40"
value="&dtml-classMetaType;">
</TD>
</TR>
<dtml-if show_class_id>
<TR>
<td align="left" valign="top">
<div class="form-label">
Class Id
</div>
</td>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="class_id" SIZE="40"
value="&dtml-class_id;">
</TD>
</TR>
</dtml-if>
<TR>
<td align="left" valign="top">
<div class="form-optional">
Icon Path
</div>
</td>
<TD ALIGN="LEFT" VALIGN="TOP">
<INPUT TYPE="TEXT" NAME="icon" SIZE="40"
value="&dtml-classIcon;">
</TD>
</TR>
<TR>
<td align="left" valign="top">
<div class="form-label">
Icon Image
</div>
</td>
<TD ALIGN="LEFT" VALIGN="TOP">
<dtml-if classIcon>
<img src="&dtml.url_quote-SCRIPT_NAME;/&dtml.url_quote-classIcon;?t=<dtml-var ZopeTime fmt=second>" border="0"><br>
</dtml-if>
<INPUT TYPE="file" NAME="file" SIZE="25" VALUE="">
</TD>
</TR>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value="Save Changes" />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-with "_(management_view='Subobjects')">
<dtml-var manage_tabs>
</dtml-with>
<form action="manage_edit" method="post">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<table>
<tr>
<td align="left" valign="top">
<div class="form-label">
Select the kinds of things<br>
that can be added to objects<br>
of this kind:
</div>
</td>
<td>
<div class="form-element">
<select name="meta_types:list" size=10 multiple>
<dtml-with "_(selected=selected_meta_types())">
<dtml-in possible_meta_types mapping>
<option
<dtml-if "name in selected">selected</dtml-if>
>&dtml-name;</option>
</dtml-in>
</dtml-with>
</select>
</div>
</td>
</tr>
<tr><td colspan=2>
<div class="form-label">
Objects should appear in folder lists?
<input type=checkbox name=isFolderish value="Y"
<dtml-if isFolderish>CHECKED</dtml-if>
>
</div>
</td>
</tr>
<tr>
<td align="left" valign="top" colspan="2">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value="Save Changes" />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
<dtml-var manage_page_header>
<dtml-with "_(management_view='Views')">
<dtml-var manage_tabs>
</dtml-with>
<form action="&dtml-URL1;" method="post">
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr class="list-header">
<td align="left" valign="top">
&nbsp;
</td>
<td align="left" valign="top">
<div class="form-label">
Name
</div>
</td>
<td align="left" valign="top">
<div class="form-label">
Method
</div>
</td>
<td align="left" valign="top">
<div class="form-label">
Help Topic
</div>
</td>
<dtml-in data mapping>
<tr>
<td align="left" valign="top">
<input type="checkbox" name="selected:list"
value="&dtml-label;" />
</td>
<td align="left" valign="top">
<div class="form-text">
&dtml-label;
</div>
</td>
<td align="left" valign="top">
<div class="form-element">
<select name="actions:list">
<dtml-in zclass_candidate_view_actions>
<option
<dtml-if "_['sequence-item'] == action">SELECTED
</dtml-if>>&dtml-sequence-item;</option>
</dtml-in>
</select>
</div>
</td>
<td align="left" valign="top">
<div class="form-element">
<select name="helps:list">
<option></option>
<dtml-in "getProductHelp().helpValues()">
<option
<dtml-if "_.has_key('help') and (_.len(help) >= 2) and _.getitem('sequence-item').id() == help[1]">SELECTED</dtml-if>>&dtml-id;</option>
</dtml-in>
</select>
</div>
</td>
</tr>
</dtml-in>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top" colspan="3">
<div class="form-element">
<input class="form-element" type="submit" value=" Change "
name="manage_edit:method">
<input class="form-element" type="submit" value=" Delete "
name="manage_delete:method">
<input class="form-element" type="submit" value=" First "
name="manage_first:method">
</div>
</td>
</tr>
</table>
</form>
<p class="form-help">
To create a new view, enter a name for the view and select the
method that implements the view and the help topic to be used
for the view.
</p>
<form action="manage_add" method="post">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Name
</div>
</td>
<td align="left" valign="top">
<input type="text" name="label" size="20" value="" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Method
</div>
</td>
<td align="left" valign="top">
<div class="form-element">
<select name="action">
<dtml-in zclass_candidate_view_actions>
<option>&dtml-sequence-item;</option>
</dtml-in>
</select>
</div>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Help Topic
</div>
</td>
<td align="left" valign="top">
<div class="form-element">
<select name="help">
<option></option>
<dtml-in "getProductHelp().helpValues()">
<option>&dtml-id;</option>
</dtml-in>
</select>
</div>
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top" colspan="3">
<div class="form-element">
<input class="form-element" type="submit" name="submit" value=" Add " />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
##############################################################################
#
# Copyright (c) 2004 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""ZClass tests
$Id$
"""
import os, sys
import unittest
import ZODB.tests.util
import transaction
from zope.testing import doctest
# XXX need to update files to get newer testing package
class FakeModule:
def __init__(self, name, dict):
self.__dict__ = dict
self.__name__ = name
def setUp(test):
test.globs['some_database'] = ZODB.tests.util.DB()
module = FakeModule('ZClasses.example', test.globs)
sys.modules[module.__name__] = module
def tearDown(test):
transaction.abort()
test.globs['some_database'].close()
del sys.modules['ZClasses.example']
def tearDown27(test):
transaction.abort()
test.globs['db'].close()
def test_suite():
return unittest.TestSuite((
doctest.DocFileSuite("_pmc.txt", setUp=setUp, tearDown=tearDown),
doctest.DocFileSuite("ZClass.txt", setUp=setUp, tearDown=tearDown),
doctest.DocFileSuite("27.txt", tearDown=tearDown27,
globs=dict(__file__=__file__),
),
))
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment