[Zope3-checkins] CVS: Zope3/lib/python/Zope/App/OFS/Services - field.py:1.1.2.1 zpt.py:1.1.2.1 configure.zcml:1.17.8.2 interfaces.py:1.1.2.4 view.py:1.1.2.2
Jim Fulton
jim@zope.com
Thu, 12 Dec 2002 10:20:25 -0500
Update of /cvs-repository/Zope3/lib/python/Zope/App/OFS/Services
In directory cvs.zope.org:/tmp/cvs-serv23093/lib/python/Zope/App/OFS/Services
Modified Files:
Tag: AdapterAndView-branch
configure.zcml interfaces.py view.py
Added Files:
Tag: AdapterAndView-branch
field.py zpt.py
Log Message:
Got view service and view registration working TTW (sort of).
This includes a new "View Package". You set up a view package with
default registration parameters. Then, as you add ZPT templates to the
package, they are automatically registered as views.
There are lots of rough edges that need to be smoothed out after the
sprint and before this branch merge.
=== Added File Zope3/lib/python/Zope/App/OFS/Services/field.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""Component location field.
$Id: field.py,v 1.1.2.1 2002/12/12 15:19:54 jim Exp $
"""
__metaclass__ = type
from Zope.Schema.IField import IField
from Zope.Schema import Field
from Zope.Schema.Exceptions import ValidationError
from Zope.App.Traversing import traverse
from Zope.App.ComponentArchitecture.InterfaceField import InterfaceField
from Zope.Exceptions import NotFoundError
class IComponentLocation(IField):
"""A field containing a component path.
"""
type = InterfaceField(
title = u"An interface that must be implemented by the component.",
required = True,
readonly = True,
)
class ComponentLocation(Field):
__implements__ = IComponentLocation
_type = unicode
def __init__(self, type, *args, **kw):
self.type = type
super(ComponentLocation, self).__init__(*args, **kw)
def _validate(self, value):
super(ComponentLocation, self)._validate(value)
if not value.startswith('/'):
raise ValidationError("Not an absolute path", value)
try:
component = traverse(self.context, value)
except NotFoundError:
raise ValidationError("Path for non-existent object", value)
if not self.type.isImplementedBy(component):
raise ValidationError("Wrong component type")
=== Added File Zope3/lib/python/Zope/App/OFS/Services/zpt.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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.
#
##############################################################################
"""
$Id: zpt.py,v 1.1.2.1 2002/12/12 15:19:54 jim Exp $
"""
import re
from Interface import Interface
from Interface.Attribute import Attribute
import Zope.Schema
from Persistence import Persistent
from Zope.ContextWrapper import ContextMethod
from Zope.Proxy.ContextWrapper import getWrapperContainer
from Zope.Security.Proxy import ProxyFactory
from Zope.App.OFS.Content.IFileContent import IFileContent
from Zope.PageTemplate.PageTemplate import PageTemplate
from Zope.App.PageTemplate.Engine import AppPT
from interfaces import IZPTTemplate
class ZPTTemplate(AppPT, PageTemplate, Persistent):
__implements__ = IZPTTemplate
contentType = 'text/html'
source = property(
# get
lambda self: self.read(),
# set
lambda self, text: self.pt_edit(text.encode('utf-8'), self.contentType)
)
def pt_getContext(self, view, **_kw):
# instance is a View component
namespace = super(ZPTTemplate, self).pt_getContext(**_kw)
namespace['view'] = view
namespace['request'] = view.request
namespace['context'] = view.context
return namespace
def render(self, view, *args, **keywords):
if args:
args = ProxyFactory(args)
kw = ProxyFactory(keywords)
namespace = self.pt_getContext(view, args=args, options=kw)
return self.pt_render(namespace)
# Adapter for ISearchableText
from Zope.App.index.text.interfaces import ISearchableText
tag = re.compile(r"<[^>]+>")
class SearchableText:
__implements__ = ISearchableText
__used_for__ = IZPTTemplate
def __init__(self, page):
self.page = page
def getSearchableText(self):
text = self.page.source
if isinstance(text, str):
text = unicode(self.page.source, 'utf-8')
# else:
# text was already Unicode, which happens, but unclear how it
# gets converted to Unicode since the ZPTPage stores UTF-8 as
# an 8-bit string.
if self.page.contentType.startswith('text/html'):
text = tag.sub('', text)
return [text]
=== Zope3/lib/python/Zope/App/OFS/Services/configure.zcml 1.17.8.1 => 1.17.8.2 ===
--- Zope3/lib/python/Zope/App/OFS/Services/configure.zcml:1.17.8.1 Wed Dec 11 06:41:08 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/configure.zcml Thu Dec 12 10:19:54 2002
@@ -3,12 +3,16 @@
xmlns:browser="http://namespaces.zope.org/browser"
>
+<!-- Configuration registries -->
+
<content class=".Configuration.ConfigurationRegistry">
<require permission="Zope.ManageServices"
interface=".ConfigurationInterfaces.IConfigurationRegistry"
/>
</content>
+<!-- Adapter Service -->
+
<content class=".adapter.AdapterService">
<implements interface="Zope.App.OFS.Annotation.IAttributeAnnotatable." />
<factory id="Zope.App.OFS.Services.AdapterService"
@@ -33,6 +37,67 @@
/>
</content>
+<!-- View Service -->
+
+<content class=".view.ViewService">
+ <implements interface="Zope.App.OFS.Annotation.IAttributeAnnotatable." />
+ <factory id="Zope.App.OFS.Services.ViewService"
+ permission="Zope.ManageServices"
+ />
+ <require permission="Zope.ManageServices"
+ interface=".ConfigurationInterfaces.IConfigurable"
+ attributes="getRegisteredMatching"
+ />
+</content>
+
+<content class=".view.ViewConfiguration">
+ <require
+ permission="Zope.ManageServices"
+ interface=".interfaces.IViewConfiguration"
+ set_schema=
+ "Zope.App.OFS.Services.ConfigurationInterfaces.IConfiguration"
+ />
+ <require
+ permission="Zope.ManageServices"
+ interface="Zope.App.OFS.Container.IDeleteNotifiable."
+ />
+</content>
+
+<content class=".view.PageConfiguration">
+ <require
+ permission="Zope.ManageServices"
+ interface=".interfaces.IPageConfiguration"
+ set_schema=
+ "Zope.App.OFS.Services.ConfigurationInterfaces.IConfiguration"
+ />
+ <require
+ permission="Zope.ManageServices"
+ interface="Zope.App.OFS.Container.IDeleteNotifiable."
+ />
+</content>
+
+<!-- Page Templates -->
+
+<content class=".zpt.ZPTTemplate">
+ <factory
+ id="Zope.app.services.zpt.template"
+ permission="Zope.ManageServices"
+ title="ZPT Template"
+ description="Page Template" />
+
+ <require
+ permission="Zope.View"
+ attributes="__call__" />
+
+ <require
+ permission="Zope.ManageServices"
+ interface=".interfaces.IZPTTemplate"
+ set_schema=".interfaces.IZPTTemplate" />
+
+ <implements
+ interface="Zope.App.OFS.Annotation.IAttributeAnnotatable." />
+</content>
+
<include package=".ServiceManager" />
<include package=".AuthenticationService" />
<include package=".LocalEventService" />
@@ -42,8 +107,9 @@
<include package=".CachingService" />
<include package=".ObjectHub" />
<include package=".ErrorReportingService" />
-<include package=".Browser" />
<include package=".PrincipalAnnotationService" />
<include package=".SessionService" />
+
+<include package=".Browser" />
</zopeConfigure>
=== Zope3/lib/python/Zope/App/OFS/Services/interfaces.py 1.1.2.3 => 1.1.2.4 ===
--- Zope3/lib/python/Zope/App/OFS/Services/interfaces.py:1.1.2.3 Wed Dec 11 09:10:24 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/interfaces.py Thu Dec 12 10:19:54 2002
@@ -18,8 +18,10 @@
from ConfigurationInterfaces import IConfiguration
from Zope.App.ComponentArchitecture.InterfaceField import InterfaceField
-from Zope.Schema import BytesLine, TextLine
+from Zope.Schema import BytesLine, TextLine, Text
from Interface import Interface
+from Zope.App.OFS.Services.field import ComponentLocation
+from Zope.ComponentArchitecture.IPresentation import IPresentation
class IAdapterConfigurationInfo(Interface):
@@ -66,10 +68,11 @@
description = u"The presentation type of a view",
readonly = True,
required = True,
+ type = IPresentation,
)
factoryName = BytesLine(
- title=u"The dotted name of a factory for creating the adapter",
+ title=u"The dotted name of a factory for creating the view",
readonly = True,
required = True,
)
@@ -78,6 +81,7 @@
title = u"View name",
readonly = True,
required = True,
+ min_length = 1,
)
layer = BytesLine(
@@ -85,6 +89,7 @@
description = u"The skin layer the view is registered for",
required = False,
readonly = True,
+ min_length = 1,
default = "default",
)
@@ -98,3 +103,51 @@
"""
+class IZPTTemplate(Interface):
+ """ZPT Templates for use in views
+ """
+
+ contentType = BytesLine(
+ title=u'Content type of generated output',
+ required=True,
+ default='text/html'
+ )
+
+ source = Text(
+ title=u"Source",
+ description=u"""The source of the page template.""",
+ required=True)
+
+ def render(context, request, *args, **kw):
+ """Render the page template.
+
+ The context argument is bound to the top-level 'context'
+ variable. The request argument is bound to the top-level
+ 'request' variable. The positional arguments are bound to the
+ 'args' variable and the keyword arguments are bound to the
+ 'options' variable.
+
+ """
+
+class IPageConfigurationInfo(IViewConfigurationInfo):
+
+ factoryName = BytesLine(
+ title=u"The dotted name of a factory for creating the view",
+ readonly = True,
+ required = False,
+ )
+
+ template = ComponentLocation(
+ title = u"Page template",
+ required = False,
+ readonly = True,
+ type = IZPTTemplate,
+ )
+
+class IPageConfiguration(IConfiguration, IPageConfigurationInfo):
+
+ def getView(object, request):
+ """Return a page for the object.
+ """
+
+
=== Zope3/lib/python/Zope/App/OFS/Services/view.py 1.1.2.1 => 1.1.2.2 ===
--- Zope3/lib/python/Zope/App/OFS/Services/view.py:1.1.2.1 Wed Dec 11 09:10:24 2002
+++ Zope3/lib/python/Zope/App/OFS/Services/view.py Thu Dec 12 10:19:54 2002
@@ -33,9 +33,12 @@
from Zope.App.ComponentArchitecture.NextService import getNextService
from Zope.ComponentArchitecture import getSkin
-from interfaces import IViewConfiguration
-from adapter import PersistentAdapterRegistry
+from Zope.Proxy.ProxyIntrospection import removeAllProxies
+from Zope.App.Traversing import getPhysicalRoot, traverse
+from Zope.Exceptions import NotFoundError
+from interfaces import IViewConfiguration, IPageConfiguration
+from adapter import PersistentAdapterRegistry
class ViewService(Persistent):
@@ -141,12 +144,34 @@
view = registry.active().getView(object, request)
return view
- views = getNextService(self, 'Views')
+ views = getNextService(self, 'Views')
return views.queryView(object, name, request, default)
queryView = ContextMethod(queryView)
+ def getDefaultViewName(self, object, request):
+ "See Zope.ComponentArchitecture.IViewService.IViewService"
+
+ name = self.queryDefaultViewName(object, request)
+
+ if name is None:
+ raise NotFoundError, \
+ 'No default view name found for object %s' % object
+
+ return name
+
+ getDefaultViewName = ContextMethod(getDefaultViewName)
+
+ def queryDefaultViewName(self, object, request, default=None):
+ "See Zope.ComponentArchitecture.IViewService.IViewService"
+
+ # XXX: need to do our own defaults as well.
+ views = getNextService(self, 'Views')
+ return views.queryDefaultViewName(object, request, default)
+
+ queryDefaultViewName = ContextMethod(queryDefaultViewName)
+
def getRegisteredMatching(self,
required_interfaces=None,
presentation_type=None,
@@ -206,3 +231,53 @@
getView = ContextMethod(getView)
+class PageConfiguration(ViewConfiguration):
+
+ __implements__ = IPageConfiguration
+
+ def __init__(self,
+ forInterface, viewName, presentationType,
+ factoryName, template,
+ layer='default'):
+ super(PageConfiguration, self).__init__(
+ forInterface, viewName, presentationType,
+ factoryName, layer)
+
+ self.template = template
+
+ def getView(self, object, request):
+ sm = getServiceManager(self)
+
+ if self.factoryName:
+ factory = sm.resolve(self.factoryName)
+ else:
+ factory = DefaultFactory
+
+ view = factory(object, request)
+
+ # This is needed because we need to do an unrestricted traverse
+ root = removeAllProxies(getPhysicalRoot(sm))
+
+ template = traverse(root, self.template)
+
+ return BoundTemplate(template, view)
+
+ getView = ContextMethod(getView)
+
+
+class DefaultFactory:
+
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+class BoundTemplate:
+
+ def __init__(self, template, view):
+ self.template = template
+ self.view = view
+
+ def __call__(self, *args, **kw):
+ return self.template.render(self.view, *args, **kw)
+
+