.. _upgrade_notes:

Upgrade notes
=============

This document outlines how to update Grok applications so that they
continue to work with newer versions of Grok.  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.

.. _upgrade_notes_1.0b2:

Upgrading to 1.0b2 (2009-09-15)
-------------------------------

* The default permission is now ``zope.View`` as a replacement for
  ``zope.Public``.  You need to add this permission as a default
  permission to all users (use ``zope.Anybody``). This requires a
  change to ``site.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`` in ``site.zcml`` or
  ``ftesting.zcml``. This will lead to an error, as Grok does not
  define ``grok.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.

  .. _`Paste Deploy`: http://pythonpaste.org/deploy/

  **Warning**. Please be aware that the ``parts/data`` and
  ``parts/log`` directories are deprecated and will not be used
  anymore. The only reasons there are still ``[data]`` and ``[log]``
  sections in the new ``buildout.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 new
  ``etc`` directory has appeared.

  The templates for config files are now in ``etc`` - these get
  generated by buildout into ``parts/etc``.  Find more information on
  configuration and settings in ``etc/README.txt``.

  The ``Data.fs`` file is now placed in ``var/filestorage``. Please
  copy your backed-up version of ``Data.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`` and ``parts/app`` will be deleted when
  you re-run buildout. This means that ``parts/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`` to
  ``bin/grokpy`` to avoid conflicts with virtualenv.

* Old ``buildout.cfg`` contain a ``find-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 that ``megrok.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`` and
  ``CodeView``.  This split got reverted. Grok's behavior is still the
  same as in the 1.0a versions - views and the ``render`` method continue
  to work as they did before.

.. _upgrade_notes_1.0a1:

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 a
  ``grok.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.

.. _upgrade_notes_0.14:

Upgrading to 0.14
-----------------

* The ``grok.Skin`` class has been removed in favour of a
  ``grok.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 of ``IBrowserRequest``.

* The ``grok.admin`` subpackage has been factored out to a separate
  package ``grokui.admin``. To have the Grok admin UI available in
  your environment, add ``grokui.admin`` to the required packages in
  the ``setup.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
                        ],

.. _upgrade_notes_0.13:

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 string ``A 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 the ``execute``
  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 may

  - set 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 as ``martian.directive``), and then the ``get``
  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`` and
  ``priority`` as class-level variables. These have been changed to
  the ``martian.component`` and the ``martian.priority`` directives
  that take the value as its first argument. The new
  ``martian.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
  use ``grok.util.applySkin``. This because
  ``zope.publisher.http.appySkin`` was removed again in later versions
  of ``zope.publisher``.

* The ``url`` method on ``ViewletManager`` and ``Viewlet`` was
  removed. Instead you can easily access the ``url`` method of the
  view itself from within a viewlet or viewlet manager, and the
  ``view`` name is also available in viewlet templates. There are also
  new ``viewlet`` and ``viewletmanager`` namespaces in the viewlet
  templates. Note that ``view`` in a viewlet thus means something else
  than what it does before. Previous uses of ``view`` in a viewlet
  template should be renamed to ``viewlet``.

.. _upgrade_notes_0.12:

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
  manual ``include`` statements (except the one that includes ``grok``
  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 upgrade ``grokproject``::

    $ 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.

.. _upgrade_notes_0.11:

Upgrading to 0.11
-----------------

* ``grok.define_permission`` has been removed in favour of a
  ``grok.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()`` and ``grok.description()``
  directives on the class.

* ``grok.grok`` and ``grok.grok_component`` have been deprecated.  If
  you need them for tests (which is their only legimitate use), you
  should import them both from ``grok.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`` and ``templates`` keyword
  arguments.  If they need access to these values, they can now get
  them as module annotations from the ``module_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 the ``martian.interfaces.IGrokker``
  interface.  A minimal specification of the ``grok()`` method is
  therefore::

    def grok(self, name, obj, **kw):
        ...

  though grokkers will likely want to take ``module_info`` as well as
  ``config`` 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 to ``grok``, you likely
  need to update the signature of the ``grok()`` method like described
  above.


Upgrading to 0.10
-----------------

There were no incompatible changes.
