Upgrade notes¶
This document outlines how to update Grok applications so that they continue to
work with newer versions of the Grok Toolkit. This document only describes
changes involving incompatibilities or deprecations, not new features (please
refer to CHANGES.txt
for those).
Warning. Please be sure to always backup your data (especially the
Data.fs
file) before you perform upgrades.
Upgrading to 1.5 (2012-05-02)¶
To upgrade your Grok based project, make sure your project’s buildout.cfg
extends from the versions.cfg
of the latest Grok Toolkit release. This file
can be found here:
http://grok.zope.org/releaseinfo/1.5/versions.cfg
Then re-run bootstrap.py
in your project to prevent potential
zc.buildout
version conflicts. Then run bin/buildout
to get the latest
versions of all of the packages that comprise the Grok Toolkit.
Upgrading to 1.4 (2011-04-04)¶
To upgrade your Grok based project, make sure your project’s buildout.cfg
extends from the versions.cfg
of the latest Grok Toolkit release. This file
can be found here:
http://grok.zope.org/releaseinfo/1.4/versions.cfg
Then re-run bootstrap.py
in your project to prevent potential
zc.buildout
version conflicts. Then run bin/buildout
to get the latest
versions of all of the packages that comprise the Grok Toolkit.
Upgrading to 1.3 (2011-01-20)¶
To upgrade your Grok based project, make sure your project’s buildout.cfg
extends from the versions.cfg
of the latest Grok Toolkit release. This file
can be found here:
http://grok.zope.org/releaseinfo/1.3/versions.cfg
Then re-run bootstrap.py
in your project to prevent potential
zc.buildout
version conflicts. Then run bin/buildout
to get the latest
versions of all of the packages that comprise the Grok Toolkit.
Extra notes:
For newly created projects using the grokproject tool, z3c.testsetup has been removed in favor of manual registration of tests. Even though tests discovery and registration through
z3c.testsetup
should still work for existing projects, it is advisable to start registering tests “manually”. More documentation concerning this topic is forthcoming. See also thetests.py
module generated by thegrokproject
tool for examples.The ‘static’ directory is no longer automatically grokked and registered as a
DirectoryResource
for serving static resources. Serving static resources is being superseded by the Fanstatic library and WSGI components.Newly created project using the
grokproject
tool will have the infrastructure set up for serving static resources, and a compatibility layer has been created through zope.fanstatic. This compatibility layer will allow for computing URLs to resources in Zope Page Templates and in view code.The compatibility layer will also set the
base_url
necessary for the Fanstatic WSGI components to automatically inject resource inclusions in the<head>
section of the rendered HMTL, and for serving the resources. Having the Fanstatic WSGI components serve the static resources will off-load this task from Grok, generally improving the application’s performance.In order to update your current Grok project to the most recent Grok Toolkit release, you need to register a Fanstatic
Library
for each of the static directories your project may have. Registering the ‘static’ directory involves three steps:Add zope.fanstatic and fanstatic to the install_requires in your project’s
setup.py
. If you are using z3c.autoinclude in yourconfigure.zcml
, the necessary component registrations inzope.fanstatic
will be done automatically.If you do not use
z3c.autoinclude
, includezope.fanstatic
in yourconfigure.zcml
.Include the following code in
resource.py
:from fanstatic import Library library = Library(PACKAGENAME, 'static')
In the
setup.py
of your project, add the following entry point (again, for each ‘static’ directory your project may have)'fanstatic.libraries': [ 'PACKAGENAME = PACKAGENAME.resource:library' ]
Where the
PACKAGENAME
should be replaced with the dotted package name in which the ‘static’ directory resides.The
grok.DirectoryResource
components have not been removed from Grok. So, the custom directory resources in your project should continue to work unchanged.The way templates are associated to view components has changed. In general, this should not lead to problems, just less spurious warnings when starting your Grok application.
The default views that were rendered in case of application errors (like for
NotFound
exceptions, orUnauthorized
exceptions used to be done through the now deprecatedzope.app.http
andzope.app.exception
packages. These packages have been replaced by thezope.errorview
package.In case your application imports from the aformentiond deprecated package, you should either include these packages in the
install_requires
section in your project’ssetup.py
or port the code to usezope.errorview
- the later is the recommend practice.
Upgrading to 1.2 (2010-10-26)¶
To upgrade your Grok based project, make sure your project’s buildout.cfg
extends from the versions.cfg
of the latest Grok Toolkit release. This file
can be found here:
http://grok.zope.org/releaseinfo/1.2/versions.cfg
Then re-run bootstrap.py
in your project to prevent potential
zc.buildout
version conflicts. Then run bin/buildout
to get the latest
versions of all of the packages that comprise the Grok Toolkit.
Extra notes:
In Grok 1.2 the “zdaemon” support has been removed. If your project still relied on this method of starting and stopping the server you will need to update your prokject.
The easiest way for find what parts and file to add, is to create a new project using the
grokproject
tool and then to compare its structure to your project’s structure. Look for the “debug_ini” and “deploy_ini” parts in thebuildout.cfg
file and the corresponding configuration file templates.A large numner of
zope.app.
dependencies have been removed. Even though most of these packages just contained backwards compatibility imports, your application might still contain imports from thesezope.app.
packages.The best way to update this, is to carefully search for
zope.app.
imports in your project and to rewrite them to the new import locations. Note though, that in rare cases, this might break persisted object in your database.If this is the case, you will need to add the particular
zope.app.
package to theinstall_requires
section in thesetup.py
of your project. After a re-run of./bin/buildout
these package are now again available to your project.In general it is good practice to explicitely list the dependencies of your project in the
setup.py
. In other words: if your project imports from packages, these packages should be listed in theinstall_requires
of your project’ssetup.py
.One specific case of a
zope.app.
depdendency that got removed and replaced iszope.app.testing
that is used in the test setup of your project. Most of the functionality inzope.app.testing
has been rebuild inzope.component.testlayer
,zope.app.appsetup
, andzope.app.wsgi.testlayer
.Again, the easiest way to upgrade this part of your project, is to look a freshly created project using the
grokproject
tool. There, the test setup code uses the “new style” test layers for functional testing.In some case the configuration step of a dependency is not triggered anymore, where it used to be before most of the
zope.app.
dependencies got removed. If this is the case (for example for components in in zope.pluggableauth.plugins), you will need to trigger the configuration yourself from your project’sconfigure.zcml
like so:<include package="[PACKAGE_TO_CONFIGURE]" />
or, for a specific
*.zcml
file in package:<include package="[PACKAGE_TO_CONFIGURE]" file="[ZCML_FILE]"/>
Upgrading to 1.1 (2010-05-18)¶
z3c.testsetup dependency has been removed from grok. If you use grok.testing.register_all_tests in your testsetup, make sure to require
z3c.testsetup
(and alsozope.app.testing
, if you use functional tests) in setup.py of your project and use:import z3c.testsetsetup z3c.testsetup.register_all_tests(...)
where you used
grok.testing.register_all_tests(...)
before.
Upgrading to 1.1rc1 (2010-02-25)¶
When upgrading to a newer version of Grok, you should refer to the newest list of versions as defined for this release of Grok.
For Grok 1.1rc1, download the following file:
http://grok.zope.org/releaseinfo/grok-1.1rc1.cfg
And replace
versions.cfg
in your project with this file. Then run:./bin/buildout
Upgrading to 1.1a2 (2009-12-22)¶
When upgrading to a newer version of Grok, you should refer to the newest list of versions as defined for this release of Grok.
For Grok 1.1a2, download the following file:
http://grok.zope.org/releaseinfo/grok-1.1a2.cfg
And replace
versions.cfg
in your project with this file. Then run:./bin/buildout
Upgrading to 1.1a1 (2009-11-17)¶
When upgrading to a newer version of Grok, you should refer to the newest list of versions as defined for this release of Grok.
For Grok 1.1a1, download the following file:
http://grok.zope.org/releaseinfo/grok-1.1a1.cfg
And replace
versions.cfg
in your project with this file. Then run:./bin/buildout
Upgrading to 1.0b2 (2009-09-15)¶
The default permission is now
zope.View
as a replacement forzope.Public
. You need to add this permission as a default permission to all users (usezope.Anybody
). This requires a change tosite.zcml
as follows:<grant permission="zope.View" principal="zope.Anybody" />
If you do not make this change, all of your views will be unavailable for anonymous and the system will ask the user for a password.
This change allows you to protect Grok views that come with the default permission by modifying your
site.zcml
.If you used a previous version of Grok or grokproject you may still have a reference to
grok.View
insite.zcml
orftesting.zcml
. This will lead to an error, as Grok does not definegrok.View
anymore. It’s safe to remove such references.When upgrading to a newer version of Grok, you should refer to the newest list of versions as defined for this release of Grok.
For Grok 1.0b2, download the following file:
http://grok.zope.org/releaseinfo/grok-1.0b2.cfg
And replace
versions.cfg
in your project with this file.There have been a lot of changes in grokproject and the project layout it generates. This gives you a short description of how you can upgrade your existing Grok project that was generated with an older version of grokproject.
You should upgrade grokproject as follows:
$ easy_install -U grokproject
grokproject now creates a project based on Paste Deploy, along with a few other changes to the way various files are managed.
Warning. Please be aware that the
parts/data
andparts/log
directories are deprecated and will not be used anymore. The only reasons there are still[data]
and[log]
sections in the newbuildout.cfg``structure is to make sure we don't accidentally throw away important data. Back up at least any important ``Data.fs
(which contains the ZODB object database of your app) before making any changes to a project, or when you upgrade any deployment.To switch over your project to use a new layout, create a new, empty project with grokproject and compare it with your current layout. You can then compare it with your existing project layout and make the appropriate changes to your project.
There have been changes to
setup.py
,buildout.cfg
and a newetc
directory has appeared.The templates for config files are now in
etc
- these get generated by buildout intoparts/etc
. Find more information on configuration and settings inetc/README.txt
.The
Data.fs
file is now placed invar/filestorage
. Please copy your backed-up version ofData.fs
in there to reuse your older ZODB database.Log files are now placed in
var/log
.Before re-running buildout to generate the new templates, please be aware that
parts/zopectl
andparts/app
will be deleted when you re-run buildout. This means thatparts/zopectl/access.log
will be removed, and you may want to backup this file first.After making these adjustments, you can now run
buildout
for the project.Start the instance now like:
bin/paster serve parts/etc/deploy.ini
or with:
bin/projectname-ctl fg
Alternatively there’s a profile available that can help debugging errors in your application:
bin/paster serve parts/etc/debug.ini
When using this profile it is not the
zope.publisher
that handles the exceptions that are raised, but a special middleware is. This middleware then provides a pdb-like debugging user interface in the browser.Note that this includes IUnauthorized exceptions not being handled by zope, that would’ve prevented any login mechanism to work when debugging.
However, there is a configuration option called
exempt-exceptions
available in the debug.ini that determines what exceptions should still be handled by zope. By default debug.ini files created by grokproject will exempt the IUnauthorized exceptions from being reraised and thus normal authentication mechanism continue to work:[app:zope] use = egg:${egg}#debug filter-with = translogger exempt-exceptions = zope.security.interfaces.IUnauthorized
Interpreter name has been changed from
bin/python
tobin/grokpy
to avoid conflicts with virtualenv.Old
buildout.cfg
contain afind-links
line like this:find-links = http://download.zope.org/distribution/
You should be able to safely remove this, as this points to a repository of old releases that Grok doesn’t depend on any more.
If you have problems after removing it and re-running
bin/buildout
, you can add it again however. We know thatmegrok.form
for instance depends on a release that was only available in this repository.Note: in 1.0b1 we used to have a split between
View
andCodeView
. This split got reverted. Grok’s behavior is still the same as in the 1.0a versions - views and therender
method continue to work as they did before.
Upgrading to 1.0b1 (2009-09-14)¶
This release happened was never completed. See the upgrade documentation for 1.0b2 instead.
Upgrading to 1.0a1¶
The
grok.RESTProtocol
class has been removed in favour of agrok.restskin()
directive for interfaces. For instance, if you previously registered a REST layer as a skin like so:class IMyLayer(grok.IRESTLayer): pass class MyRestProtocol(grok.RESTProtocol): grok.layer(IMyLayer)
You can now simply write:
class IMyLayer(grok.IRESTLayer): grok.restskin('myskin')
As you can see,
IRESTLayer
has been introduced as a baseclass for defining REST layers.
Upgrading to 0.14¶
The
grok.Skin
class has been removed in favour of agrok.skin()
directive for interfaces. For instance, if you previously registered a browser layer as a skin like so:class IMyLayer(grok.IGrokLayer): pass class MySkin(grok.Skin): grok.layer(IMyLayer)
You can now simply write:
class IMyLayer(grok.IBrowserRequest): grok.skin('myskin')
As you can see,
IGrokLayer
has also been removed, in favour of the exposure ofIBrowserRequest
.The
grok.admin
subpackage has been factored out to a separate packagegrokui.admin
. To have the Grok admin UI available in your environment, addgrokui.admin
to the required packages in thesetup.py
of your package.A new Grok application will have an install_requires parameter that looks like this:
install_requires=['setuptools', 'grok', 'grokui.admin', 'z3c.testsetup', # Add extra requirements here ],
Upgrading to 0.13¶
The directive implementations changed tremendously with the upgrade to Martian 0.10. Custom implementations of both directives (see next bullet point) and grokkers will have to be adjusted.
Since the vast majority of directives are class directives, the most common places where information set by directives has to be read are class grokkers (
martian.ClassGrokker
). For instance, you may have written something like this to implement a custom class grokker previously:class RobotGrokker(martian.ClassGrokker): component_class = Robot def grok(self, name, factory, module_info, config, **kw): robot_name = martian.util.class_annotation(factory, 'grok.name', '') title = martian.util.class_annotation(factory, 'grok.title', 'A robot') provides = martian.util.class_annotation(factory, 'grok.provides', None) if provides is None: martian.util.check_implements_one(factory) provides = list(zope.interface.implementedBy(factory))[0] config.action( descriminator=('robot', provides, robot_name), callable=provideRobot, args=(factory, provides, robot_name, title), ) return True
As you can see, this grokker needs to retrieve three values from the class it’s grokking (
factory
) which are all set by directives:grok.name
with the standard default, an empty string,grok.title
with a custom default, the stringA robot
,grok.provides
with a computed default.
With the new directive implementation and the extensions to Martian’s
ClassGrokker
, you are now able to write (and you should write!):def default_provides(factory, module, **data): # This function is available for import from grokcore.component.meta. # It's shown here simply to illustrate how the original grokker would # have been refactored. martian.util.check_implements_one(factory) return list(zope.interface.implementedBy(factory))[0] class RobotGrokker(martian.ClassGrokker): martian.component(Robot) martian.directive(grok.name, name='robot_name') martian.directive(grok.title, default='A Robot') martian.directive(grok.provides, get_default=default_provides) def execute(self, factory, config, robot_name, title, provides, **kw): config.action( descriminator=('robot', provides, robot_name), callable=provideRobot, args=(factory, provides, robot_name, title), ) return True
What you need to do is provide the directives in the grokker class using
martian.directive
and then implement theexecute
method which will get the class (factory
) and the configuration context (config
) as positional arguments and then the values of the directives as keyword parameters.Note that when using
martian.directive
, you mayset the name of the keyword parameter if you want it to be different than the directive’s name,
set a default value if you want it to be different from the directive’s standard default,
pass in a factory for a computed default value (
get_default
).
If you need still need to manually retrieve directive values from an object (a class, an instance or a module), you can do so by explicitly calling
bind
on the directive (which accepts the same optional parameters asmartian.directive
), and then theget
method of the bound directive, e.g.:class_context = grok.context.bind().get(factory, module=module) just_module_context = grok.context.bind().get(module=module)
In most cases it’s possible to avoid this though, and use the
martian.directive
directive on the class level.You can look at
src/grok/meta.py
in Grok to see examples.Your custom grokker could previously use
component_class
andpriority
as class-level variables. These have been changed to themartian.component
and themartian.priority
directives that take the value as its first argument. The newmartian.directive
directive was introduced above.Custom directives need to be re-implemented using Martian’s new
Directive
base class. The directive scope, the type of storage, the validator and a potential default value are all defined as class-level variables:The directive scope can either one of
martian.CLASS
,martian.MODULE
,martian.CLASS_OR_MODULE
.The type of storage can be either one of
martian.ONCE
,martian.MULTIPLE
,martian.DICT
.An optional validator may be one of
validateText
,validateInterface
,validateInterfaceOrClass
or a custom method.Unless set with a different value, the standard default value will be
None
.
For example, consider the implementation of the
grok.name
directive:class name(martian.Directive): scope = martian.CLASS store = martian.ONCE default = u'' validate = martian.validateText
Or a bit more involved (and made-up) example:
class bases(martian.Directive): scope = martian.CLASS scope = martian.ONCE default = [] # The factory is called with the parameters of the directive # and may transform the values into whatever should be stored. def factory(self, *values): return list(values) # This validator makes sure that the directive can only take # a list of classes an argument def validate(self, *values): for value in values: if not isinstance(value, type): raise GrokError("%r is not a class!" % value)
We moved to newer versions of zope packages. Grok’s versions for Zope packages are now based on the KGS list for Zope 3.4c1 (the latest list). This means your code can now get some new deprecation warnings for imports that have been moved. Please check your code and fix your imports if you get those warnings.
If you were using
zope.publisher.http.applySkin
, you now must usegrok.util.applySkin
. This becausezope.publisher.http.appySkin
was removed again in later versions ofzope.publisher
.The
url
method onViewletManager
andViewlet
was removed. Instead you can easily access theurl
method of the view itself from within a viewlet or viewlet manager, and theview
name is also available in viewlet templates. There are also newviewlet
andviewletmanager
namespaces in the viewlet templates. Note thatview
in a viewlet thus means something else than what it does before. Previous uses ofview
in a viewlet template should be renamed toviewlet
.
Upgrading to 0.12¶
Please upgrade grokproject:
$ easy_install -U grokproject
If you have existing Grok projects and you want to make use of Grok’s new autoinclusion functionality in them, you can place the following line in your project’s
configure.zcml
:<includeDependencies package=”.” />
This will cause the ZCML for
setup.py
dependencies of your package to be loaded automatically. You can now get rid of any manualinclude
statements (except the one that includesgrok
itself).For new projects created by
grokproject
, this line will be automatically be added for you and you don’t have to do anything except to upgradegrokproject
:$ easy_install -U grokproject
The convention that classes ending with -Base automatically become base classes has been removed with martian 0.9.4. Please add the grok.baseclass() directive to these classes explicitly where the ‘Base’ class convention was relied upon to preserve existing functionality.
Upgrading to 0.11¶
grok.define_permission
has been removed in favour of agrok.Permission
base class, for reasons of symmetry. Instead of writing:grok.define_permission('myapp.ViewCavePainting')
you should now write:
class View(grok.Permission): grok.name('myapp.ViewCavePainting')
If you also want to supply a title and description for the permission, use the
grok.title()
andgrok.description()
directives on the class.grok.grok
andgrok.grok_component
have been deprecated. If you need them for tests (which is their only legimitate use), you should import them both fromgrok.testing
.Grokkers should now emit configuration actions instead of registering components right away. For that they now get a new keyword argument called
config
, the configuration context. For example, a grokker that used to do this:registerSomeComponent(foo, name)
should now be doing this:
config.action( discriminator=('somecomponent', name), callable=registerSomeComponent, args=(name,) )
The discriminator should be chosen so that registrations with the same discriminator conflict (in the above example, if somebody tried to register two different components under the same name, you’d get a conflict).
Grokkers no longer get the
context
andtemplates
keyword arguments. If they need access to these values, they can now get them as module annotations from themodule_info
object like this:context = module_info.getAnnotation('grok.context') templates = module_info.getAnnotation('grok.templates')
Note that grokkers must always take arbitrary keyword arguments (
**kw
), as specified by themartian.interfaces.IGrokker
interface. A minimal specification of thegrok()
method is therefore:def grok(self, name, obj, **kw): ...
though grokkers will likely want to take
module_info
as well asconfig
explicitly:def grok(self, name, obj, module_info, config, **kw): ...
If your application defines custom grokkers and you’re getting a
TypeError
about unexpected arguments togrok
, you likely need to update the signature of thegrok()
method like described above.
Upgrading to 0.10¶
There were no incompatible changes.