[PEAK] Persistence styles, MDA, AOP, PyProtocols, and PEAK

Stephen Waterbury golux at comcast.net
Wed Jul 7 22:19:38 EDT 2004


Robert Brewer wrote:
> (replying off-list)
> No, I think I got it the first time. ;) You're using composition ("has
> a") where I use subclassing ("is a").

No, actually you *still* didn't quite get it.  ;)

>>What I have is:
>>
>>Document._schema._OntoClass__name == 'Document'
>>
>>(_schema is an OntoClass instance)
> 
> An app developer using Dejavu would write:
> 
> class Document(Unit):
>     ....
> Document.set_property('Content')
> 
> class Invoice(Document):
>     ....
> Invoice.set_property('Owner')
> 
> ...instances of Invoice would possess the properties [ID, Content,
> Owner], as well as any methods defined in class Unit, class Document, or
> class Invoice.

Right, but you have to write Python code to do that.
You are creating a new Invoice class.  In my app,
you just create a new instance of OntoClass with
__name = 'Invoice', give it those properties, and
assign it as the _schema of an instance of your
existing Document class.  You don't have to create
a new Python class:  no coding required.  In fact,
you could build the 'Invoice' OntoClass instance
at runtime by importing the definition of an 'Invoice'
ontology Class from an OWL file, and you could rebuild
the database at runtime to support it, if you choose to.
Of course, you could write Python code generators to do
that for your app, but that's a *lot* messier, IMO.  ;)

> By merging the two concepts, you save having to do parallel updates to
> the two classes; that is, you only have one class to update when adding
> new behaviors.

Ah, but I don't have to do parallel updates -- it's all
one Python class, which happens to have a _schema
attribute that is an OntoClass instance.  The Python
class automatically receives as attributes the
OntoProperties defined in the OntoClass instance,
which is contained in the Python class declaration!  ;)

> For example, here's a fragment of a real-life Invoice
> class:
> 
> class Invoice(dejavu.Unit):
>     def balance_due(self):
>         amt = self.Amount or fixedpoint.FixedPoint(0, 2)
>         paid = self.Paid or fixedpoint.FixedPoint(0, 2)
>         return amt - paid
> Invoice.set_properties({u'Amount': fixedpoint.FixedPoint,
>                         u'Paid': fixedpoint.FixedPoint,
>                         u'InventoryID': int,
>                        })
> namespace.associate(Inventory, u'ID', Invoice, u'InventoryID')
> 
> All of the attribute management (including relationship mechanisms
> between Unit classes) is handled in the superclass, leaving you to get
> on with modeling your domain.

Cool -- just a slightly different approach from mine.
Here's how it would look in PanGalactic.  Assuming Invoice
needs more behaviors than Document has (as in your example),
we would define a new Python class for it, in which it would
extend Document and its _schema would "extend" (not in the
Python sense, but in the ontological Class sense) the OntoClass
instance named 'Document' (a.k.a., Document._schema) ...

from pangalactic.enterprise.document import Document
from pangalactic.meta.ontoclass import OntoClass
from pangalactic.meta.ontoproperty import OntoProperty

class Invoice(Document):
    _schema = OntoClass(
        _OntoClass__name='Invoice',
        _OntoClass__base=Document._schema,
        _OntoClass__description="""
        A bill for something.
        """,
        _OntoClass__properties=[
        OntoProperty(
            name='amount',
            type_name='Dollars', # define this type elsewhere
            default='',
            description="""
            Total amount of the invoice in Dollars US.
            """),
        OntoProperty(
            name='paid',
            type_name='Dollars', # define this type elsewhere
            default='',
            description="""
            Total amount of the invoice in Dollars US.
            """),
        OntoProperty(
            name='items',
            type_name='Product',
            default=None,
            min_cardinality=1
            max_cardinality=0  # means no maximum :)
            description="""
            Things being billed for.
            """),
            ]) # end of _schema

    def __init__(self, **kw):
        """
        Initialize an Invoice.
        """
        Document.__init__(self, **kw)
        # this will accept any OntoProperties of Document or Invoice,
        # such as 'amount' or 'items', as kw args and assign them as
        # instance attributes.

    def getBalanceDue(self):
        return self.amount - self.paid

    def setBalanceDue(self, value):
        raise TypeError, 'Nuh uh!'

    def delBalanceDue(self):
        raise TypeError, 'Hah, nice try!'

    balance_due = property(getBalanceDue, setBalanceDue,
                           delBalanceDue, 'balance due')

So then ...

i = Invoice(amount=Dollars(50), paid=Dollars(20),
            items=[Product(id='thingy'), Product(id='otherthingy')])
i.balance_due()
>>> $30

(or something like that ... :)

Cheers,
Steve



More information about the PEAK mailing list