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'},
)
This diff is collapsed.
This diff is collapsed.
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