The startup module¶
Description
The initialization module (__init__.py) provides the script that is run when Zope is started.
Before starting the usual Zope product initialization code, we need to define a Message Factory for when this product is internationalized.
from zope.i18nmessageid import MessageFactory
exampleMessageFactory = MessageFactory('example.archetype')
The defined
MessageFactory
object will be imported with the special name “_” in most
modules, and strings like _(u“message”) will then be
extracted by i18n tools for translation.
Now, we import some useful stuff from the Archetypes
API:process_types
is useful to get the product’s content types,
associated constructors, and
Factory Type Information (FTI) data structures,
while
listTypes
can be used to list the types available in the product.
We also need to import the
utils
module from
CMFCore
to be able to use its
ContentInit
class later.
from Products.Archetypes.atapi import process_types
from Products.Archetypes.atapi import listTypes
from Products.CMFCore import utils
Python notes:
- Factory Type Information (FTI): Part of a CMF portal’s configuration, the FTI for a content type is the data structure that holds the information needed to expose a content type within the portal. From the integrator’s perspective, the FTI is the object (Factory-based Type Information object) within the portal_types component that tells CMF and Plone how to create a content from the type and how to display it.
- How exactly does ‘listTypes’ work: See those registerType() calls in your content type modules? Notice how we also import those modules (but do nothing with the import) in the ‘content’ package’s __init__.py. The registerType() call tells AT about the type so that listTypes() can find it later.
One of the important import steps : we import everything that is defined in the content sub-package, i.e. all its modules:
from content import message
Now, we import the configuration module, in order to have access to the variables it contains, such as the “Add” permission setting:
import config
Now for the real action. You define a function that is required by Zope and CMF internals to initialize our content type(s):
def initialize(context):
The first part of the code of this function generates the content types, the constructors and the Factory-based Type Informations (or FTIs) required to make your types work with the CMF:
content_types, constructors, ftis = process_types(
listTypes(config.PROJECTNAME),
config.PROJECTNAME)
The second part instantiates an object of the class ContentInit (from CMFCore), and registers your types in the CMF:
utils.ContentInit(
"%s Content" % config.PROJECTNAME,
content_types = content_types,
permission = config.ADD_CONTENT_PERMISSIONS['InstantMessage'],
extra_constructors = constructors,
fti = ftis,
).initialize(context)
Handling several content types
There is a better way to write the code that initializes the content type class with its “Add” permission and constructor, so that it still works if you define several content types. This is useful if you plan to later augment your product with additional types.
Here is the improved code:
def initialize(context):
content_types, constructors, ftis = process_types(
listTypes(config.PROJECTNAME),
config.PROJECTNAME)
# We want to register each type with its own permission,
# this will afford us greater control during system
# configuration/deployment (credit : Ben Saller)
allTypes = zip(content_types, constructors)
for atype, constructor in allTypes:
kind = "%s: %s" % (config.PROJECTNAME, atype.portal_type)
utils.ContentInit(kind,
content_types = (atype,),
permission = config.ADD_CONTENT_PERMISSIONS[atype.portal_type],
extra_constructors = (constructor,),
fti = ftis,
).initialize(context)
Python notes:
- We can use the “ADD_CONTENT_PERMISSIONS[atype.portal_type]” construct because ADD_CONTENT_PERMISSIONS references a dictionary in which the keys are the potential content types names.
- The zip() function is a Python built-in that pairs up elements of two lists. In this case, “allTypes” will be a list of tuples containing a content type from “content_types” and the corresponding constructor from “constructors”.
- If you have several content types, you should not forget to import each content module, as is done for the message example discussed here !