Skip to content

Commit

Permalink
Check if the code is up to date with the Grok trunk. Port over commen…
Browse files Browse the repository at this point in the history
…ts which have been added.

Clean unused imports.
  • Loading branch information
thefunny42 committed Jun 5, 2009
1 parent 2057e34 commit dece0cd
Show file tree
Hide file tree
Showing 7 changed files with 370 additions and 0 deletions.
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -34,6 +34,7 @@ def read(*rnames):
zip_safe=False,
install_requires=['setuptools',
'martian',
'ZODB3',
'zope.component',
'zope.interface',
'zope.app.component',
Expand Down
22 changes: 22 additions & 0 deletions src/grokcore/site/__init__.py
@@ -0,0 +1,22 @@
##############################################################################
#
# Copyright (c) 2006-2009 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.
#
##############################################################################

from grokcore.site.directive import local_utility
from grokcore.component import provides
from grokcore.site.components import Site, LocalUtility

import grokcore.site.testing

from grokcore.site.interfaces import IGrokcoreSiteAPI
__all__ = list(IGrokcoreSiteAPI)
54 changes: 54 additions & 0 deletions src/grokcore/site/components.py
@@ -0,0 +1,54 @@
##############################################################################
#
# Copyright (c) 2006-2009 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.
#
##############################################################################

from grokcore.component.interfaces import IContext

from persistent import Persistent

from zope.interface import implements

from zope.app.component.site import SiteManagerContainer

from zope.app.container.contained import Contained


class Site(SiteManagerContainer):
"""Mixin for creating sites in Grok applications.
When an application `grok.Model` or `grok.Container` also inherits
from `grok.Site`, then it can additionally support the registration
of local Component Architecture entities like `grok.LocalUtility`
and `grok.Indexes` objects; see those classes for more information.
"""


class LocalUtility(Contained, Persistent):
"""The base class for local utilities in Grok applications.
Although application developers can create local utilies without
actually subclassing `grok.LocalUtility`, they gain three benefits
from doing so. First, their code is more readable because their
classes "look like" local utilities to casual readers. Second,
their utility will know how to persist itself to the Zope database,
which means that they can set its object attributes and know that
the values are getting automatically saved. Third, they can omit
the `grok.provides()` directive naming the interface that the
utility provides, if their class only `grok.implements()` a single
interface (unless the interface is one that the `grok.LocalUtility`
already implements, in which case Grok cannot tell them apart, and
`grok.provides()` must be used explicitly anyway).
"""
implements(IContext)
103 changes: 103 additions & 0 deletions src/grokcore/site/directive.py
@@ -0,0 +1,103 @@
##############################################################################
#
# Copyright (c) 2006-2007 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.
#
##############################################################################
"""Grok directives.
"""

import grokcore.component

from grokcore.site.components import LocalUtility

from zope import interface
from zope.interface.interfaces import IInterface

import martian
from martian import util
from martian.error import GrokImportError

class local_utility(martian.Directive):
scope = martian.CLASS
store = martian.DICT

def factory(self, factory, provides=None, name=u'',
setup=None, public=False, name_in_container=None):
if provides is not None and not IInterface.providedBy(provides):
raise GrokImportError("You can only pass an interface to the "
"provides argument of %s." % self.name)

if provides is None:
provides = grokcore.component.provides.bind().get(factory)

if provides is None:
if util.check_subclass(factory, LocalUtility):
baseInterfaces = interface.implementedBy(LocalUtility)
utilityInterfaces = interface.implementedBy(factory)
provides = list(utilityInterfaces - baseInterfaces)

if len(provides) == 0 and len(list(utilityInterfaces)) > 0:
raise GrokImportError(
"Cannot determine which interface to use "
"for utility registration of %r. "
"It implements an interface that is a specialization "
"of an interface implemented by grok.LocalUtility. "
"Specify the interface by either using grok.provides "
"on the utility or passing 'provides' to "
"grok.local_utility." % factory, factory)
else:
provides = list(interface.implementedBy(factory))

util.check_implements_one_from_list(provides, factory)
provides = provides[0]

if (provides, name) in self.frame.f_locals.get(self.dotted_name(), {}):
raise GrokImportError(
"Conflicting local utility registration %r. "
"Local utilities are registered multiple "
"times for interface %r and name %r." %
(factory, provides, name), factory)

info = LocalUtilityInfo(factory, provides, name, setup, public,
name_in_container)
return (provides, name), info


class LocalUtilityInfo(object):
"""The information about how to register a local utility.
An instance of this class is created for each `grok.local_utility()`
in a Grok application's code, to remember how the user wants their
local utility registered. Later, whenever the application creates
new instances of the site or application for which the local utility
directive was supplied, this block of information is used as the
parameters to the creation of the local utility which is created
along with the new site in the Zope database.
"""
_order = 0

def __init__(self, factory, provides, name=u'',
setup=None, public=False, name_in_container=None):
self.factory = factory
self.provides = provides
self.name = name
self.setup = setup
self.public = public
self.name_in_container = name_in_container

self.order = LocalUtilityInfo._order
LocalUtilityInfo._order += 1

def __cmp__(self, other):
# LocalUtilityInfos have an inherit sort order by which the
# registrations take place.
return cmp(self.order, other.order)
46 changes: 46 additions & 0 deletions src/grokcore/site/interfaces.py
@@ -0,0 +1,46 @@
##############################################################################
#
# Copyright (c) 2006-2009 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.
#
##############################################################################

from zope.interface import Interface, Attribute


class IBaseClasses(Interface):
Site = Attribute("Mixin class for sites.")
LocalUtility = Attribute("Base class for local utilities.")


class IDirectives(Interface):
def local_utility(factory, provides=None, name=u'',
setup=None, public=False, name_in_container=None):
"""Register a local utility.
factory - the factory that creates the local utility
provides - the interface the utility should be looked up with
name - the name of the utility
setup - a callable that receives the utility as its single argument,
it is called after the utility has been created and stored
public - if False, the utility will be stored below ++etc++site
if True, the utility will be stored directly in the site.
The site should in this case be a container.
name_in_container - the name to use for storing the utility
"""

def provides(interface):
"""Explicitly specify with which interface a component will be
looked up."""


class IGrokcoreSiteAPI(IBaseClasses, IDirectives):
"""grokcore.site's public API."""

108 changes: 108 additions & 0 deletions src/grokcore/site/meta.py
@@ -0,0 +1,108 @@
#############################################################################
#
# Copyright (c) 2006-2009 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.
#
##############################################################################

from zope import component

from zope.app.container.interfaces import IContainer, IObjectAddedEvent
from zope.app.container.interfaces import INameChooser

import martian
from martian.error import GrokError

import grokcore.site


class SiteGrokker(martian.ClassGrokker):
martian.component(grokcore.site.Site)
martian.priority(500)
martian.directive(grokcore.site.local_utility, name='infos')

def execute(self, factory, config, infos, **kw):
if not infos:
return False

infos = infos.values()
for info in infos:
if info.public and not IContainer.implementedBy(factory):
raise GrokError(
"Cannot set public to True with grok.local_utility as "
"the site (%r) is not a container." %
factory, factory)

# Store the list of info objects in their "natural" order on the
# site class. They will be picked up by a subscriber doing the
# actual registrations in definition order.
factory.__grok_utilities_to_install__ = sorted(infos)
adapts = (factory, IObjectAddedEvent)

config.action(
discriminator=None,
callable=component.provideHandler,
args=(localUtilityRegistrationSubscriber, adapts),
)
return True


def localUtilityRegistrationSubscriber(site, event):
"""A subscriber that fires to set up local utilities.
"""
installed = getattr(site, '__grok_utilities_installed__', False)
if installed:
return

for info in getattr(site.__class__, '__grok_utilities_to_install__', []):
setupUtility(site, info.factory(), info.provides, name=info.name,
name_in_container=info.name_in_container,
public=info.public, setup=info.setup)

# we are done. If this subscriber gets fired again, we therefore
# do not register utilities anymore
site.__grok_utilities_installed__ = True


def setupUtility(site, utility, provides, name=u'',
name_in_container=None, public=False, setup=None):
"""Set up a utility in a site.
site - the site to set up the utility in
utility - the utility to set up
provides - the interface the utility should be registered with
name - the name the utility should be registered under, default
the empty string (no name)
name_in_container - if given it will be used to add the utility
object to its container. Otherwise a name will be made up
public - if False, the utility will be stored in the site manager. If
True, the utility will be storedin the site (it is assumed the
site is a container)
setup - if not None, it will be called with the utility as its first
argument. This function can then be used to further set up the
utility.
"""
site_manager = site.getSiteManager()

if not public:
container = site_manager
else:
container = site

if name_in_container is None:
name_in_container = INameChooser(container).chooseName(
utility.__class__.__name__, utility)
container[name_in_container] = utility

if setup is not None:
setup(utility)

site_manager.registerUtility(utility, provided=provides,
name=name)
36 changes: 36 additions & 0 deletions src/grokcore/site/subscriber.py
@@ -0,0 +1,36 @@
##############################################################################
#
# Copyright (c) 2006-2009 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.
#
##############################################################################

import grokcore.component
from zope.app.component.site import LocalSiteManager
from zope.app.container.interfaces import IObjectAddedEvent

from grokcore.site.components import Site

@grokcore.component.subscribe(Site, IObjectAddedEvent)
def addSiteHandler(site, event):
"""Add a local site manager to a Grok site object upon its creation.
Grok registers this function so that it gets called each time a
`grok.Site` instance is added to a container. It creates a local
site manager and installs it on the newly created site.
"""

sitemanager = LocalSiteManager(site)
# LocalSiteManager creates the 'default' folder in its __init__.
# It's not needed anymore in new versions of Zope 3, therefore we
# remove it
del sitemanager['default']
site.setSiteManager(sitemanager)

0 comments on commit dece0cd

Please sign in to comment.