FYI, I just finished a rough implementation of the phase 1 EIM API (primitive types, aliasing, and conversion). It's not in SVN yet (so as not to interfere with a4 work), but here is the current doctest, warts and all. (Most of the warts will be fixed when phase 2 kicks in, adding "Record" and "field" types that will produce better examples.)

Review and comments welcomed and requested.


----------------------
The Sharing Record API
----------------------

>>> import eim as sharing   # API kludge during initial dev & testing


Defining and Using Field Types
==============================

Custom Types
------------

The most basic kinds of field types can be created using the ``BytesType``, ``TextType``, ``IntType``, ``DateType``, and ``LobType`` constructors::

    >>> my_date = sharing.DateType()
    >>> my_date
    sharing.DateType(None)

Types can be given a unique URI, and they can be looked up by it::

    >>> my_text = sharing.TextType("cid:[email protected]", size=99)
    >>> my_text
    sharing.TextType('cid:[email protected]', 99)

    >>> sharing.typeinfo_for("cid:[email protected]")
    sharing.TextType('cid:[email protected]', 99)

    >>> my_text.uri
    'cid:[email protected]'

    >>> my_text.size
    99

But only one type can exist for a given URI at a given point in time::

    >>> another_text = sharing.TextType("cid:[email protected]", 99)
    Traceback (most recent call last):
      ...
    TypeError: A type already exists for 'cid:[email protected]'

    >>> del my_text     # no conflicting definition now
    >>> another_text = sharing.TextType("cid:[email protected]", 99)


Type Aliasing
-------------

The ``sharing.typedef()`` API lets you register type information for arbitrary Python objects, so that you can use existing types, kinds, etc. as field types. For example::

    >>> class my_int(int):
    ...     """This is just a demonstration type"""

    >>> sharing.typedef(my_int, sharing.IntType('cid:[email protected]'))

Now, ``my_int`` can be used directly as a field type in a ``sharing.Record`` class, instead of using the ``IntType`` object::

    >>> sharing.typeinfo_for(my_int)    # XXX demo w/field instead of typeinfo
    sharing.IntType('cid:[email protected]')

You can alias more than one object to the same type, or alias an object to an already-registered alias::

    >>> class my_int2(int):
    ...     """Another demonstration type"""

    >>> sharing.typedef(my_int2, my_int)
    >>> sharing.typeinfo_for(my_int2) is sharing.typeinfo_for(my_int)
    True

There are also built-in aliases for anonymous versions of the sizeless primitive types (``IntType``, ``LobType``, and ``DateType``), so you can use them directly in fields::

    >>> sharing.typeinfo_for(sharing.IntType)
    sharing.IntType(None)

    >>> sharing.typeinfo_for(sharing.LobType)
    sharing.LobType(None)

    >>> sharing.typeinfo_for(sharing.DateType)
    sharing.DateType(None)


Type Conversion
---------------

Because there are only five primitive EIM types (bytes, text, integer, date/time, and "lob"), it is usually necessary to convert some application- level data types to the corresponding primitive type.

For example, let's say that an application has a value that is normally represented as a hexidecimal string, but which for some reason it wants to transmit as an integer in its sharing records. The application would need to define a string converter to turn the hex string into an integer.

So let's define a ``hexint`` type that we can use in field definitions where we want to be able to supply either integers or hex strings as input when creating a record.

    >>> hexint = sharing.IntType('cid:[email protected]')

By default, there is no converter registered to convert strings to integers, although there is one for converting integers to integers::

    >>> sharing.get_converter(hexint)(23)
    23

    >>> sharing.get_converter(hexint)("23")
    Traceback (most recent call last):
      ...
    TypeError: No converter registered for values of type <type 'str'>

The ``sharing.add_converter()`` API allows you to register a conversion function to be used for a particular field or field type::

    >>> sharing.add_converter(hexint, str, lambda v: int(v,16))
    >>> sharing.get_converter(hexint)("23")
    35


XXX this doc should probably use fields for examples, so as to hide the use of get_converter(type)(value); normally this would only be called by record constructors.

XXX Need more default encoders for primitive types; only int->IntType currently works


Creating Subtypes
-----------------

Sometimes, it's useful to create a field type by copying an existing type. The ``sharing.subtype()`` function creates a new type from an existing one. The new type will be of the same primitive type, and it will "inherit" any conversion functions defined for the base type::

    >>> hexint2 = sharing.subtype(hexint)
    >>> hexint2
    sharing.IntType(None)

    >>> sharing.get_converter(hexint2)("23")
    35

XXX example of argument pass-through from ``subtype()`` to typeinfo constructor
XXX test generation-skipping in converter registration


---------
Internals
---------

TypeInfo instances are immutable once created::

    >>> t = sharing.IntType()
    >>> t.uri = "fhdsfblah"
    Traceback (most recent call last):
      ...
    TypeError: sharing.IntType instances are immutable

Misc. constructor data validation tests::

    >>> sharing.TypeInfo()
    Traceback (most recent call last):
      ...
    TypeError: sharing.TypeInfo is an abstract type; use a subtype

    >>> sharing.SizedType()
    Traceback (most recent call last):
      ...
    TypeError: size must be specified when creating a sharing.SizedType

    >>> sharing.SizedType(size=53)
    Traceback (most recent call last):
      ...
    TypeError: sharing.SizedType is an abstract type; use a subtype

    >>> sharing.BytesType()
    Traceback (most recent call last):
      ...
    TypeError: size must be specified when creating a sharing.BytesType

    >>> sharing.TextType()
    Traceback (most recent call last):
      ...
    TypeError: size must be specified when creating a sharing.TextType

No such type::

    >>> sharing.typeinfo_for('xyz:abc')
    Traceback (most recent call last):
      ...
    UnknownType: 'xyz:abc'

XXX typeinfo_for(obj) -> TypeInfo
   field -> typeinfo_for(field.type)
   descr -> typeinfo_for(descr.type)

_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

Open Source Applications Foundation "chandler-dev" mailing list
http://lists.osafoundation.org/mailman/listinfo/chandler-dev

Reply via email to