*************************************************************************
itools 0.50.0
*************************************************************************

These upgrade notes may not be complete. Thanks to report any problem you
find.

New Dependencies
================

The minimum required version of Python has been raised to 2.5.2.

The new "itools.xapian" package requires the Xapian library (xapian-core)
and its Python wrapper (xapian-bindings), version 1.0.7 or later.  To
download from "http://www.xapian.org".


Imports
=======

The package "itools.catalog" has been replaced by the package "itools.xapian",
but the changes to the API are minimal (see section below).

Other objects have been renamed across different packages, the table below
summarizes this changes.

  Before (alphabetical order)    Now
  ----------------------------   ---------------------------
  catalog.*                      xapian.*
  datatypes.FileName             vfs.FileName
  datatypes.XML                  datatypes.XMLContent
  gettext.Message                gettext.POUnit
  ical.icalendar                 ical.iCalendar
  i18n.Message                   srx.Message
  i18n.Multilingual              (REMOVED)
  stl.STLNameError               stl.STLError
  tmx.Message                    tmx.TMXUnit
  tmx.Note                       tmx.TMXNote
  tmx.TMX                        tmx.TMXFile
  web.Node                       web.Resource
  web.Root                       web.RootResource
  xliff.Note                     xliff.XLFNote
  xliff.Translation              xliff.XLFUnit
  xliff.XLIFF                    xliff.XLFFile
  xml.AbstractNamespace          xml.XMLNamespace
  xml.set_namespace              xml.register_namespace


Global API
==========

The prototype for the functions "get_abspath", "get_version" and "setup"
has changed.  The required globals namespace has been dropped:

  Before                          Now
  -----------------------------   ------------------
  get_abspath(globals(), '...')   get_abspath('...')
  get_version(globals())          get_version()
  setup(globals())                setup()


itools.csv
=============

(1) Some methods and class variables (for the Table class) have been
renamed:

  Before                          Now
  -----------------------------   -------------------------
  Table.schema                    Table.record_schema
  Table.get_datatype              Table.get_record_datatype
  Table.get_value                 Table.get_record_value

(2) The 'Property' class now takes keyword parameters for the property
parameters:

  # Before
  Property(u'hello', {'language': 'en'})
  Property(value, parameters)

  # Now
  Property(u'hello', language='en')
  Property(value, **parameters)

(3) Now 'Unicode' table fields that are 'multiple' are considered to be
multilingual.

This means that now it is not possible to have a 'Unicode' field that
is multiple and monolingual.  Such fields must be revised to change the
datatype to something else than 'Unicode', for example 'String'.

Also, table files with fields that are desired to be multilingual must be
upgraded, since they are required to have the 'language' parameter:

  # Before
  title:hello world

  # Now
  title;language=en:hello world

(4) The 'Table.get_field_title' method has been moved to ikaaro.


itools.gettext
==============

(1) The way to translate a message from a Python file has considerably
changed:

  # Before
  message = u'...'
  self.gettext(message)

  # Now
  from itools.gettext import MSG
  message = MSG(u'...')
  message.gettext()

And the "DomainAware" class has disappeared:

  # Before
  from itools.gettext import DomainAware
  class MyClass(DomainAware):
      class_domain = 'my_project'
      ...

  # Now
  class MyClass(object):
      ...

(2) There are some changes to the 'POFile' API too:

  Before               Now
  -------------------  ----------------
  POFile.get_messages  POFile.get_units
  POFile.set_message   POFile.add_unit
  POUnit.msgid         POUnit.source
  POUnit.msgstr        POUnit.target


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

It has been changed how to avoid caching a handler:

  # Before
  file = folder.get_handler('...', cache=False)

  # Now
  database = folder.database
  database.set_use_cache(False)
  file = folder.get_handler('...')
  database.set_use_cache(True)

Some other API changes:

  Before               Now
  -------------------  --------------------
  Handler.mimetype     Handler.get_mimetype
  Python.get_messages  Python.get_units


itools.i18n
===========

The segmentation code has been moved to the itools.srx package.  The
implementation is completely different, now it is based on the SRX
file format.


itools.ical
===========

API changes:

  # Before
  iCalendar.get_datatype
  icalendarTable._load_state_from_ical_file

  # Now
  iCalendar.get_record_datatype
  icalendarTable.load_state_from_ical_file


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

  Before                Now
  --------------------  --------------------
  ODFFile.get_messages  ODFFile.get_units


itools.stl
==========

(1) The URI has changed:

  # Before
  xmlns:stl="http://xml.itools.org/namespaces/stl"

  # Now
  xmlns:stl="http://www.hforge.org/xml-namespaces/stl"

(2) Now the STL attributes must always be prefixed:

  # Before
  <stl:block repeat="...">

  # Now
  <stl:block stl:repeat="...">

(3) The 'stl_lookup' method has been dropped, use dictionaries instead.


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

(1) The architecture of the web framework has considerably changed.  Before
a URL was mapped to a method, now it is mapped to a instance of the 'BaseView'
class:

  # Before
  from itools.web import Node
  class MyClass(Node):
      view__access__ = True
      def view(self, context):
          ...

  # Now
  from itools.web import Resource, BaseView
  class MyClassView(BaseView):
      access = True
      def GET(self, resource, context):
          ...

  class MyClass(Resource):
      view = MyClassView()

(2) When a view is not explicitly defined, now the server will use the
'default view'.  Example:

  # Before
  class MyClass(Node):
      def GET(self, context):
          return context.uri.resolve2(';view')

  # Now
  class MyClass(Resource):
      default_view_name = 'view'

This example also illustrates that now we do not recommend to redirect to a
default view, but to return straight away the response to the client:

  # Before
  GET / HTTP/1.1
  HTTP/1.1 302 Found

  GET /;view HTTP/1.1
  HTTP/1.1 200 OK

  # Now
  GET / HTTP/1.1
  HTTP/1.1 200 OK

(3) The naming has changed.  What before was sometimes called 'node' and
sometimes 'object', is now named 'resource'.  Some attributes of the
context object have changed their name too.  The table below summarizes
these changes.

  Before (alphabetical order)    Now
  ----------------------------   ---------------------------
  Context.method                 Context.view_name
  Context.object                 Context.resource
  Node._get_object               Resource._get_resource
  Node._has_object               Resource._has_resource
  Node.copy_object               Resource.copy_resource
  Node.del_object                Resource.del_resource
  Node.get_object                Resource.get_resource
  Node.get_objects               Resource.get_resources
  Node.get_real_object           Resource.get_real_resource
  Node.has_object                Resource.has_resource
  Node.move_object               Resource.move_resource
  Node.set_object                Resource.set_resource
  Node.traverse_objects          Resource.traverse_resources

(4) The prototype of the 'Context.get_form_value' method has changed, the
order of its optional parameters have been swapped:

  # Before
  Context.get_form_value(name, default=None, type=String)

  # Now
  Context.get_form_value(name, type=String, default=None)

Other context methods have been removed, the functionality they provided is
now available through the views interface.  These methods are:

  # Removed
  Context.build_form_namespace(schema, method=None)
  Context.check_form_input(schema)

(5) The access control API has changed too, now the 'is_access_allowed' method
expects a 'View' instead of a method name.

  # Before
  AccessControl.is_access_allowed(user, resource, method_name)

  # Now
  AccessControl.is_access_allowed(user, resource, view)

(6) The only CSS classes defined byt itools.web have been renamed:

  Before           Now
  --------------   -----------------
  field_required   field_is_required
  missing          field_is_missing

(7) The prototype for the server class has changed, after the unification
of the error and debug logs:

  # Before
  Server(..., error_log=error_log, debug_log=debug_log, ...)

  # Now
  Server(..., event_log=event_log, debug=True, ...)


itools.xapian (was itools.catalog)
==================================

EqQuery has been removed, PhraseQuery must be used instead.  The results
should be the same.

  Before                          Now
  ------------------------------  -------------------------------
  query = EqQuery('id', 'foo')    query = PhraseQuery('id', 'foo')


itools.xml
==========

(1) Now the parser returns a different value for DOCUMENT_TYPE events.

  # Before
  if event == DOCUMENT_TYPE:
      name, system_id, public_id, has_internal_subset = value
      if public_id is None:
          print '<!DOCTYPE %s SYSTEM "%s">' % (name, system_id)
      elif ...

  # Now
  if event == DOCUMENT_TYPE:
      name, doctype = value
      print '<!DOCTYPE %s %s>' % (name, doctype.to_str())

(2) The way to define a new XML namespace has changed.  Most notably now
it is possible to precisely define the attributes of each element.

  # Before
  from itools.xml import AbstractNamespace, set_namespace
  class MyNamespace(AbstractNamespace):
      class_uri = myuri
      class_prefix = myprefix
      elements_schema = {
        'a': ...,
	...
      }
      datatypes = {
        'hfef': ...,
	...
      }
  set_namespace(MyNamespace)

  # Now
  from itools.xml import XMLNamespace, ElementSchema, register_namespace
  myelements = [
      ElementSchema('a', ['href']),
      ...
  ]
  my_namespace = XMLNamespace(myuri, myprefix, myelements)
  register_namespace(my_namespace)


(3) The public namespaces API has changed too.  These are some of the changes:

  # Before
  from itools.xml import get_element_schema
  get_element_schema(tag_uri, tag_name).get_attr_datatype(att_uri, att_name)

  # Now
  from itools.xml import get_attr_datatype
  get_attr_datatype(tag_uri, tag_name, att_uri, att_name)

The 'get_attr_datatype' function accepts the optional parameter 'attributes',
since the datatype of an attribute may depend on other attributes.  The
example below illustrates this, and also how the 'is_translatable' method
has been replaced:

  # Before
  from itools.xml import get_namespace
  ns = get_namespace(tag_uri)
  if ns.is_translatable(tag_uri, tag_name, attributes, attr_name):
      ...

  # Now
  dt = get_attr_datatype(tag_uri, tag_name, att_uri, att_name, attributes)
  if isinstance(dt, Unicode):
      ...

  Before                          Now
  ------------------------------  -------------------------------
  AbstractNamespace.get_element   XMLNamespace.get_element_schema
  AbstractNamespace.get_datatype  XMLNamespace.get_attr_datatype


(4) There are other API changes.

  # Before
  element = html_doc.get_body()
  print element.get_body_as_html()

  # Now
  print html_doc.get_body_as_html()


itools.datatypes
================

(1) The "default" value of a datatype must not be used directly, because you could
alter a mutable object. Call the "get_default()" accessor:

  Before                          Now
  ------------------------------  -------------------------------
  datatype.default                datatype.get_default()

In order to avoid altering the default value, we have started to write
"freezed" versions of mutable objects like lists and dictionaries. Currently
only lists are supported:

  >>> from itools.utils import freeze
  >>> freeze([])
  frozenlist([])

This will prevent default values or constants at large to be altered.

We have written the "frozenlist" class as a derivate of the built-in list but
preventing any change to the state of the list.

(2) When you set a datatype as multiple ("multiple=True" argument), you will
receive an empty list as the default value. To receive your own initialized
list as the default value, just set "default" as before:

  Unicode(multiple=True, default=freeze([u'']))

Freezing a mutable object is a good custom. Tuples have another semantic in
Python.

(3) Now all datatypes are classes, even when you set arguments. A new class is
dynamically generated to store your own values. It should not affect your code
in any way.

(4) The DynamicEnumerate class has disappeared. The Enumerate class is now
able to do the same job:

  Before                               Now
  -----------------------------------  -------------------------------
  DynamicEnumerate(resource=resource)  Enumerate(resource=resource)

If you have inherited from DynamicEnumerate and wrote instance methods, just
turn them into class methods using "classmethod".
