
**************************************************************************
itools 0.14.0
**************************************************************************

1. Requirements
===============

With itools 0.14 the minimum version of Python required is 2.5


2 itools.vfs (replaces itools.resources)
========================================

The package "itools.resources" has been replaced by the new package
"itools.vfs".

2.1 A richer API
················

The new package "itools.vfs" offers a more rich API. Basically where
before we needed two lines:

    >>> from itools.resources import get_resource
    >>>
    >>> resource = get_resource('hello.txt')
    >>> mtime = resource.get_mtime()

Now one line will be enough:

    >>> from itools import vfs
    >>>
    >>> mtime = vfs.get_mtime('hello.txt')

2.2 Files are Python files
··························

The function "vfs.open" replaces "get_resource". The difference, it
returns real Python files, instead of "file resources". The code:

    >>> file = get_resource('hello.txt')
    >>> file.open()
    >>> [WORK WITH THE FILE]
    >>> file.close()

Now will be written:

    >>> file = vfs.open('hello.txt')
    >>> [WORK WITH THE FILE]
    >>> file.close()

The API offered by resource files was already very close to Python
files, so in most cases no further modifications will be needed.


2.3 Folders can still be opened
·······························

The function "vfs.open" works for folders like before, so the code:

    >>> folder = get_resource('/tmp')

Will be just rewritten to:

    >>> folder = vfs.open('/tmp')

And keep working.


2.4 There are no more "memory" resources
········································

There is no equivalent to "memory" resources in "itools.vfs", the
good news is that you won't need them. Memory resources were there
only because of "itools.handlers", but "itools.handlers" don't
needs them anymore.


3. itools.handlers
==================

3.1 Handlers are attached to URIs
·································

Now handlers are attached to a URI instead of to a resource.

Before:

    >>> from itools.resources import get_resource
    >>> from itools.handlers.Text import Text
    >>>
    >>> resource = get_resource('hello.txt')
    >>> handler = Text(resource)
    >>> print handler.resource
    <itools.resources.file.File object at 0xb7a1f18c>

Now:

    >>> from itools.handlers.Text import Text
    >>>
    >>> handler = Text('hello.txt')
    >>> print handler.uri
    file:///tmp/hello.txt

3.2 New handlers are attached to nothing
········································

New handlers are built like before, with (optional) keyword parameters,
but they are attached to nothing.

Before:

    >>> handler = Text()
    >>> print handler.resource
    <itools.resources.memory.File object at 0xb7b2392c>

Now:

    >>> handler = Text()
    >>> print handler.uri
    None

3.3 Loading
···········

With 0.13 the method "load_state" was both able to reload the state
from the handler's resource, or to use another resource. With 0.14
the new method "load_state_from" must be used to load from another
uri.

Before:

    >>> handler.load_state()
    >>> handler.load_state(resource)

Now:

    >>> handler.load_state()
    >>> handler.load_state_from(uri)

In addition file handlers have other two load methods, to load the
handler from an open file or from a byte string, respectively:

    >>> handler.load_state_from_file(file)
    >>> handler.load_state_from_string(string)

3.4 Saving
··········

Similarly there are two methods to save instead of one:

Before:

    >>> handler.save_state()
    >>> handler.save_state(resource)

Now:

    >>> handler.save_state()
    >>> handler.save_state_to(uri)

And file handlers have a third method to save to open files:

    >>> handler.save_state_to_file(file)

3.5 Writing handler classes
···························

First, the Python slots must be defined for all handler classes, these
must include the five mandatory instance variables ("uri", "timestamp",
"parent", "name", "real_handler") plus the variables that define the
handler's state. For example:

    class VCard(File):

        __slots__ = ['uri', 'timestamp', 'parent', 'name', 'real_handler',
                     'version', 'xxx']

With itools 0.14 the handler's state is not stored in the instance
variable "state", which has been removed, but directly into the instance.
And the method to specialize for files is not anymore "_load_state(resource)",
but "_load_state_from_file(file)".

Before:

    def _load_state(self, resource):
	state = self.state
        ...
        state.version = version
        ...

Now:

    def _load_state_from_file(self, file):
        ...
        self.version = version
        ...

Also, the method "get_skeleton" has been replaced with the method "new",
which directly initializes the handler's state.

Before:

    def get_skeleton(self, version="2.1"):
        skeleton = ("BEGIN:VCARD\n"
                    "VERSION:2.1\n"
                    "END:VCARD\n")
        return skeleton % version

Now:

    def new(self, version="2.1"):
        self.version = "2.1"

3.6 The registry
················

Last, the registry for handler classes is now implemented in the module
"registry".

Before:

    class VCard(File):
        class_mimetypes = ['text/v-card']
        class_extenstion = 'vcf'

    File.register_handler_class(VCard)

Now:

    from itools.handler.registry import register_handler_class

    class VCard(File):
        class_mimetypes = ['text/v-card']
        class_extenstion = 'vcf'

    register_handler_class(VCard)

3.6 Other API changes
····················· 

The handler for images (itools.handlers.Image.Image) provides the method
"get_size", which returns a tuple with the width and the height of the
image. This method replaces "get_width" and "get_height".


4. itools.catalog
=================

The catalog's API is the same, but the format has changed. This just
mean that old catalog instances must be removed, and rebuilt with the
new code.


5. itools.web
=============

5.1 Getting parameters from the request
·······································

Before the request parameters were implicitly mapped to the Python
method definition. Now, instead, the context object is always passed
and the parameters must be explicitly retrieved from it.

Before:

    def edit_metadata(self, title, description, **kw):
        ...

Now:

    def edit_metadata(self, context):
        title = context.get_form_value('title')
        description = context.get_form_value('description')

The complete API is:

    context.get_form_keys()
    context.get_form_value(name, default=None)
    context.get_form_values(name)
    context.has_form_value(name)

Other methods that expect the "context" parameter are:

  - before_traverse

5.2 Removed the special case ":list"
····································

In itools 0.13 we still used the ":list" descriptor from the old Zope days.
Now the new context API allows as to do the same thing in a more reliable
way.

Before:

    <select name="colors:list" multiple="multiple">
      <option value="red" />
      <option value="green" />
      <option value="blue" />
    </select>

    def edit_colors(self, colors, **kw):
        self.colors = colors

Now:

    <select name="colors" multiple="multiple">
      <option value="red" />
      <option value="green" />
      <option value="blue" />
    </select>

    def edit_colors(self, context):
        self.colors = context.get_form_values('colors')

[Note] For a discussion on the importance to be splicit see the documentation
for the Standard Library module cgi, http://docs.python.org/lib/node472.html

5.3 Upload files
················

Before the uploaded files were memory resources, now it is a tuple with three
elements: the filename, the mimetype and the data (a string).

Before:

    def f(self, **kw):
	file = kw['file']

	filename = file.name
	mimetype = file.get_mimetype()
	body = file.read()

Now:

    def f(self, context):
	file = context.get_form_value('file')

	filename, mimetype, body = file

5.4 Redirections made easy
··························

Before to make a redirection we either used the context API or raised an
exception. Now the common way is to return a URI object.

Before:

    from itools.web import get_context
    from itools.web.exceptions import UserError

    def edit_metadata(self, title, description, **kw):
        if not title:
            raise UserError, "the title is mandatory"
        ...
        context = get_context()
        context.redirect(';edit_metadata_form')

Now:

    from itools import uri

    def edit_metadata(self, context):
        if not title:
            ref = ';edit_metadata_form?message=the title is mandatory'
            return uri.get_reference(ref)
        ...
        return uri.get_reference(';edit_metadata_form')

5.5 Not Found
·············

Before when the requested resource was not found the variable "context.handler"
was set to the root handler. Now it is None.


6. itools.cms
=============

6.1 Re-arranging the code
·························

Some files have been renamed, hence the imports must be updated.

The module "archive" has been moved to the "handlers" subpackage. Before:

  from itools.cms.archive import ZipArchive, TarArchive

Now:

  from itools.handlers.archive import ZipArchive, TarArchive

The new module "binary" keeps most binary handlers. Before:

  from itools.cms.images import Image
  from itools.cms.flash import Flash
  from itools.cms.office import PDF, OfficeDocument, MSWord, MSExcel, \
      MSPowerPoint, OOffice, OOWriter, OOCalc, OOImpress

Now:

  from itools.cms.binary import Image
  from itools.cms.binary import Flash
  from itools.cms.binary import PDF, OfficeDocument, MSWord, MSExcel, \
      MSPowerPoint, OOffice, OOWriter, OOCalc, OOImpress

The new module "handlers" keeps some low-level handlers (those that have
their own parsing logic). Before:

  from itools.cms.metadata import Metadata
  from itools.cms.Group import ListOfUsers

Now:

  from itools.cms.handlers import Metadata
  from itools.cms.handlers import ListOfUsers

6.2 The registry
················

The registry for itools.cms handler classes is now separated from the
standard registry for base handlers.

Before:

    class Forum(Folder)
        class_id = 'forum'

    Folder.register_handler_class(Forum)

Now:

    from itools.cms.registry import register_object_class

    class Forum(Folder)
        class_id = 'forum'

    register_object_class(Forum)

6.3 More on redirections
························

Following on redirections, the utilty function "comeback" has been replaced
by the more high level "context.come_back".

Before:

    from itools.cms.utils import comeback

    def edit_metadata(self, title, description, **kw):
        ...
        message = u"Changes saved. New title: %(title)s."
        message = self.gettext(message) % {'title': title}
        comeback(message)

Now:

    def edit_metadata(self, context):
        ...
        message = u"Changes saved. New title: $title."
        return context.come_back(message, title=title)

Basically the new method calls to "gettext" to translate the text string.
And we use a more friendly format for variable substitution.

6.4 Views and subviews
······················

While redefining the methods "get_views" and "get_subviews" still works
(so the code is backwards compatible), now there is preferred way: to
use the class variable "class_views".

Before:

    def get_views(self):
        return ['browse_thumbnails', 'new_resource_form', 'edit_metadata_form']

    def get_subviews(self, view):
        if view in ['browse_thumbnails', 'browse_list', 'browse_image']:
            return ['browse_thumbnails', 'browse_list', 'browse_image']
        return []

Now:

    class_views = [['browse_thumbnails', 'browse_list', 'browse_image'],
                   ['new_resource_form'],
                   ['edit_metadata_form']]

6.5 Skins
·········

Now most skin methods expect the context as parameter. These are:

  - build_namespace
  - get_navigation_menu
  - get_tabs

Also, the STL namespace has changed a little, the following names have been
removed:

  - user/info/logout
  - user/login_url

So the templates will need to be changed.


6.6 Access Control
··················

The access control has been redisigned (and is now basically provied by
"itools.web.access"). Instead of every handler class to inherit from
AccessControl, now we search back in the parth (acquire) the access
control point.

Before:

    if handler.is_allowed_to_view():
	...

Now:

    ac = handler.get_access_control()
    if ac.is_allowed_to_view(context.user, handler):
        ...

And now the __access__ declarations are only allowed to be either False,
True or the name of the control method as a byte string. Other notations
are definitely obsolete.

Before:

   edit__access__ = is_allowed_to_edit

Now:

   edit__access__ = 'is_allowed_to_edit'

6.7 Roles replace Groups
························

The groups concept and code has been replaced by "Roles".

This is maybe the most intrusive change. Basically every group becomes a
role, and the container of the roles must be role aware, this is to say,
must inherit from the class "RoleAware".

The database instances will need to be upgraded, check the upgrade method
in "itools.cms.root.Root" where this is done for the vanilla itools.cms

6.8 All files are workflow aware
································

And private default. The effect this may cause is that after an upgrade
many images and other files that with 0.13 were accessible for anonymous
users, become with 0.14 private.

May need an upgrade script to automatically publish the images. Or to do
it manually.


6.9 Versioning
··············

The versioning code has been simplified in preparation for the git backend
in a future release. Basically now we don't keep old versions of the files,
so the new code has a smaller functional scope.

On the other hand now all files are versioning aware, not just text files.

Note that the upgrade code removes the archive.

6.10 Updating instances
······················

Firs and very important, make a backup copy of the database.

Upgrading an instance of a vanilla itools.cms is a two steps process:
(1) run "icms-update", (2) reindex the catalog. This is the list of
changes made by "icms-update":

  - Remove the archive (".archive")
  - Rename the metadata files from ".xxx.metadata" to "xxx.metadata"
  - Change the group admins to the role admins.
  - Remove the group reviewers.
  - Remove the "en.po" resource (the message catalog).

To reindex the catalog you will need to start the application, log in,
and go to the URL "http://xxx/;catalog_form", then click the update
catalog button.

If you are upgrading your custom application it is likely you will need
to redefine the upgrade method. Check the one from vanilla "itools.cms"
for the example.




