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.testsetupshould still work for existing projects, it is advisable to start registering tests “manually”. More documentation concerning this topic is forthcoming. See also thetests.pymodule generated by thegrokprojecttool for examples.The ‘static’ directory is no longer automatically grokked and registered as a
DirectoryResourcefor serving static resources. Serving static resources is being superseded by the Fanstatic library and WSGI components.Newly created project using the
grokprojecttool 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_urlnecessary 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
Libraryfor 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.fanstaticwill be done automatically.If you do not use
z3c.autoinclude, includezope.fanstaticin yourconfigure.zcml.Include the following code in
resource.py:from fanstatic import Library library = Library(PACKAGENAME, 'static')
In the
setup.pyof your project, add the following entry point (again, for each ‘static’ directory your project may have)'fanstatic.libraries': [ 'PACKAGENAME = PACKAGENAME.resource:library' ]
Where the
PACKAGENAMEshould be replaced with the dotted package name in which the ‘static’ directory resides.The
grok.DirectoryResourcecomponents 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
NotFoundexceptions, orUnauthorizedexceptions used to be done through the now deprecatedzope.app.httpandzope.app.exceptionpackages. These packages have been replaced by thezope.errorviewpackage.In case your application imports from the aformentiond deprecated package, you should either include these packages in the
install_requiressection in your project’ssetup.pyor 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
grokprojecttool and then to compare its structure to your project’s structure. Look for the “debug_ini” and “deploy_ini” parts in thebuildout.cfgfile 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_requiressection in thesetup.pyof your project. After a re-run of./bin/buildoutthese 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_requiresof your project’ssetup.py.One specific case of a
zope.app.depdendency that got removed and replaced iszope.app.testingthat is used in the test setup of your project. Most of the functionality inzope.app.testinghas 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
grokprojecttool. 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.zcmllike so:<include package="[PACKAGE_TO_CONFIGURE]" />
or, for a specific
*.zcmlfile 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.cfgin 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.cfgin 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.cfgin your project with this file. Then run:./bin/buildout
Upgrading to 1.0b2 (2009-09-15)¶
The default permission is now
zope.Viewas a replacement forzope.Public. You need to add this permission as a default permission to all users (usezope.Anybody). This requires a change tosite.zcmlas 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.Viewinsite.zcmlorftesting.zcml. This will lead to an error, as Grok does not definegrok.Viewanymore. 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.cfgin 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/dataandparts/logdirectories 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.cfgand a newetcdirectory 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.fsfile is now placed invar/filestorage. Please copy your backed-up version ofData.fsin 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/zopectlandparts/appwill be deleted when you re-run buildout. This means thatparts/zopectl/access.logwill be removed, and you may want to backup this file first.After making these adjustments, you can now run
buildoutfor 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.publisherthat 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-exceptionsavailable 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.IUnauthorizedInterpreter name has been changed from
bin/pythontobin/grokpyto avoid conflicts with virtualenv.Old
buildout.cfgcontain afind-linksline 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.formfor instance depends on a release that was only available in this repository.Note: in 1.0b1 we used to have a split between
ViewandCodeView. This split got reverted. Grok’s behavior is still the same as in the 1.0a versions - views and therendermethod 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.RESTProtocolclass 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,
IRESTLayerhas been introduced as a baseclass for defining REST layers.
Upgrading to 0.14¶
The
grok.Skinclass 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,
IGrokLayerhas also been removed, in favour of the exposure ofIBrowserRequest.The
grok.adminsubpackage has been factored out to a separate packagegrokui.admin. To have the Grok admin UI available in your environment, addgrokui.adminto the required packages in thesetup.pyof 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.namewith the standard default, an empty string,grok.titlewith a custom default, the stringA robot,grok.provideswith 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.directiveand then implement theexecutemethod 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
bindon the directive (which accepts the same optional parameters asmartian.directive), and then thegetmethod 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.directivedirective on the class level.You can look at
src/grok/meta.pyin Grok to see examples.Your custom grokker could previously use
component_classandpriorityas class-level variables. These have been changed to themartian.componentand themartian.prioritydirectives that take the value as its first argument. The newmartian.directivedirective was introduced above.Custom directives need to be re-implemented using Martian’s new
Directivebase 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,validateInterfaceOrClassor a custom method.Unless set with a different value, the standard default value will be
None.
For example, consider the implementation of the
grok.namedirective: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.appySkinwas removed again in later versions ofzope.publisher.The
urlmethod onViewletManagerandViewletwas removed. Instead you can easily access theurlmethod of the view itself from within a viewlet or viewlet manager, and theviewname is also available in viewlet templates. There are also newviewletandviewletmanagernamespaces in the viewlet templates. Note thatviewin a viewlet thus means something else than what it does before. Previous uses ofviewin 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.pydependencies of your package to be loaded automatically. You can now get rid of any manualincludestatements (except the one that includesgrokitself).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_permissionhas been removed in favour of agrok.Permissionbase 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.grokandgrok.grok_componenthave 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
contextandtemplateskeyword arguments. If they need access to these values, they can now get them as module annotations from themodule_infoobject 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.IGrokkerinterface. A minimal specification of thegrok()method is therefore:def grok(self, name, obj, **kw): ...
though grokkers will likely want to take
module_infoas well asconfigexplicitly:def grok(self, name, obj, module_info, config, **kw): ...
If your application defines custom grokkers and you’re getting a
TypeErrorabout 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.
