Re: [Zope3-Users] newbie design questions for UI to external data

2006-02-14 Thread Gary Poster


On Feb 13, 2006, at 10:33 PM, Shaun Cutts wrote:


Um...

I guess I must have asked too many questions at once :)


:-) and this is still a bit much for me.


I've implemented
a first pass of a container for external data and got it working on  
some

of my collections.

I've included the (first pass of the) base DBContainer and DBContained
objects for criticism, and would be very grateful if anyone would like
to take a crack at it.


It looks like an interesting approach--more low-level than I would  
have expected for a first cut, and *maybe* more low-level than  
necessary.  I wish I had more time to look at it.


Keep in mind, this is my first time working with the system, so I'm  
sure

I'm going about some things the wrong way. In particular, I already
think:

1) Instead of have the contained object update the container, I should
rely on the event notification system.


Events are a tool for disconnected notification.  calling a method on  
an object is sending a message directly to the interested party.  Not  
everything should be an event.  If a communication between two  
components is a core aspect of your design, maybe direct method calls  
are more appropriate.



2) Right now, the system works by translating objects at the border
(in IExternalContainer). Some translation is necessary, for  
instance, to

move from mx.DateTime to datetime.datetime, but still I think I should
somehow be making use of the adaptor interface.


If there's not an object to adapt then you have to start somewhere.   
My glance at the code seemed to show that you were making a  
reasonable choice.  Another approach might be to have an abstract  
row object that could represent any columns (a dict or something),  
and named adapters registered for the row interface plus the name of  
the generating table.  I dunno, do what your app needs and refine it  
as you discover what works.


3) Along these same lines, IDBContainer._containedType should  
really be

an interface (Object( schema = IDBContained ))

Note: is there a tutorial on writing containers anywhere I should have
read? I mainly figured this out by banging on it and fishing around in
the code. I'd love to figure out, for instance, what is really  
happening
with the traversals (with some interaction diagrams). I do think it  
was

harder than it should have been. (But, then again, I think that about
most things...:))


Don't know of a tutorial.  Sounds like you are interested in  
traversal, though, which is different.   Look at zope.app.traversing,  
or zope.app.container.traversal.  The headline is that there are two  
kinds of traversal: URL path traversal and TALES path traversal.   
They have different adapters.



BTW in my humble opinion, ILocation.__name__ is not well named. When I
first got an error referring to __name__ I thought it was expecting a
class object. And what happens when, for some strange reason, someone
wants to put a class in a container, and doesn't like its default  
name?


Not sure if that's a real use case for an ILocation.

That said, it's a reasonable POV to say that Zope shouldn't claim  
__*__ names.  But we do, so, well, yeah, we do. ;-)


Gary
___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users


RE: [Zope3-Users] newbie design questions for UI to external data

2006-02-14 Thread Shaun Cutts
Gary,

Thanks for the reply.

 On Feb 13, 2006, at 10:33 PM, Shaun Cutts wrote:
 
  Um...
 
  I guess I must have asked too many questions at once :)
 
 :-) and this is still a bit much for me.
 
  I've implemented
  a first pass of a container for external data and got it working on
  some
  of my collections.
 
  I've included the (first pass of the) base DBContainer and
DBContained
  objects for criticism, and would be very grateful if anyone would
like
  to take a crack at it.
 
 It looks like an interesting approach--more low-level than I would
 have expected for a first cut, and *maybe* more low-level than
 necessary.  I wish I had more time to look at it.

If there were anything more higher-level, I would be happy I will
eventually be needing paged collections to, though, so I can't give up
too much control.

 
  Keep in mind, this is my first time working with the system, so I'm
  sure
  I'm going about some things the wrong way. In particular, I already
  think:
 
  1) Instead of have the contained object update the container, I
should
  rely on the event notification system.
 
 Events are a tool for disconnected notification.  calling a method on
 an object is sending a message directly to the interested party.  Not
 everything should be an event.  If a communication between two
 components is a core aspect of your design, maybe direct method calls
 are more appropriate.

The problem now is that the default edit view uses __setitem__ for the
contained object, so I get one db update per column, whereas (I hope!)
the event is fired after all the column updates are complete. Not a
problem for the prototype, but maybe annoying in production system when
Postgres is busier with other users as well. Of course, I may be
overriding the default edit view anyway

So the problem isn't the coupling between DBContained and DBContainer
per se. Its sort of like I want the editView to enforce a transaction
protocol, and want to use the Event as a proxy for commit.

Note: I don't think I want dirty object in the system; otherwise I could
use a lazy protocol where the container just checks -- say at
demarshalling time (but probably on shutdown at least, if we are
interrupted?) -- whether it has any updates to write. If I did want to
go to a lazy protocol, is there a way to register things for getting
triggered on shutdown.

 
  2) Right now, the system works by translating objects at the
border
  (in IExternalContainer). Some translation is necessary, for
  instance, to
  move from mx.DateTime to datetime.datetime, but still I think I
should
  somehow be making use of the adaptor interface.
 
 If there's not an object to adapt then you have to start somewhere.
 My glance at the code seemed to show that you were making a
 reasonable choice.  Another approach might be to have an abstract
 row object that could represent any columns (a dict or something),
 and named adapters registered for the row interface plus the name of
 the generating table.  I dunno, do what your app needs and refine it
 as you discover what works.
 
I actually do have a row object from my database code... but (as I
learned) it is a bit of a pain to use directly, since: 1) datatypes are
somewhat non-standard (dates, particularly), and 2) it is a bit messy to
use with annotations because Row uses __getattribute__, though this is
probably a design flaw in the Row class hierarchy.

My thought was that I might want to be adapting my row objects (or their
interfaces to be precise). Indeed, I am, but in a nonstandard way, as
IExternalDatabase-derivatives do the translation. My plan now is: have
the DBContained base class be a protoadapter that does all the column
datatype translations and validation; its subclasses will adapt specific
Row-derived classes, which have concrete sets of columns.

I guess there is no particular machinery to use to present this pattern:
one hierarchy adapts another hierarchy?

  3) Along these same lines, IDBContainer._containedType should
  really be
  an interface (Object( schema = IDBContained ))
 
  Note: is there a tutorial on writing containers anywhere I should
have
  read? I mainly figured this out by banging on it and fishing around
in
  the code. I'd love to figure out, for instance, what is really
  happening
  with the traversals (with some interaction diagrams). I do think it
  was
  harder than it should have been. (But, then again, I think that
about
  most things...:))
 
 Don't know of a tutorial.  Sounds like you are interested in
 traversal, though, which is different.   Look at zope.app.traversing,
 or zope.app.container.traversal.  The headline is that there are two
 kinds of traversal: URL path traversal and TALES path traversal.
 They have different adapters.

When debugging, I had a lot of problems understanding what was happening
because I didn't understand how traversal was trying to get data... It
would just be nice to have more design doc -- especially interaction
diagrams -- to refer to 

RE: [Zope3-Users] newbie design questions for UI to external data

2006-02-13 Thread Shaun Cutts
Um...

I guess I must have asked too many questions at once :) I've implemented
a first pass of a container for external data and got it working on some
of my collections.

I've included the (first pass of the) base DBContainer and DBContained
objects for criticism, and would be very grateful if anyone would like
to take a crack at it.

Keep in mind, this is my first time working with the system, so I'm sure
I'm going about some things the wrong way. In particular, I already
think:

1) Instead of have the contained object update the container, I should
rely on the event notification system.

2) Right now, the system works by translating objects at the border
(in IExternalContainer). Some translation is necessary, for instance, to
move from mx.DateTime to datetime.datetime, but still I think I should
somehow be making use of the adaptor interface. 

3) Along these same lines, IDBContainer._containedType should really be
an interface (Object( schema = IDBContained ))

Note: is there a tutorial on writing containers anywhere I should have
read? I mainly figured this out by banging on it and fishing around in
the code. I'd love to figure out, for instance, what is really happening
with the traversals (with some interaction diagrams). I do think it was
harder than it should have been. (But, then again, I think that about
most things...:))

BTW in my humble opinion, ILocation.__name__ is not well named. When I
first got an error referring to __name__ I thought it was expecting a
class object. And what happens when, for some strange reason, someone
wants to put a class in a container, and doesn't like its default name?

Thanks,
- Shaun

-

class IExternalContainer( Interface ):
an external container interface.

def add( obj ):
add 'obj'

def update( obj ):
update obj

def delete( obj ):
delete obj

def connect( obj ):
establish a connection to external database

def __iter__( ):
iterates through external objects

class IDBContainer( IContainer, ILocation ):
container that lives in zope, but contains objects
made persistent by an external container.

_database = Object( schema = IExternalContainer )
_containedType = Attribute( type of object contained )

def __setitem__( key, obj ): 
Add a IDBContained object. 

def _updateItem( key, newKey = None ):
notify that object has been modified.

If the key has been changed, 'key' should be the old
key of the object, and 'newKey' should be set to the
new key.

def __delitem__( key ):
delete item, removing it both from this view
and from external storage.

def getAttributeNames():
get names of attributes of contained object

class IDBContained( IContained, ILocation ):
Contained in IDBContainer. Must notify its parent
if it is changed. Because of this, it must also know how
to get its key.

__parent__ = Field(
constraint = ContainerTypesConstraint( IDBContainer ) )

def getZopeKey():
return ascii str or unicode key.

IDBContainer[ '__setitem__' ].precondition = ItemTypePrecondition(
IDBContained )
class DBContainer( IterableUserDict, Contained ):

Implements L{IDBContainer}

 from zope.interface.verify import verifyClass
 verifyClass( IDBContainer, DBContainer )
True


implements( IDBContainer )

# prevent browser from choosing name
nameAllowed = False

# defaults for IDBContainer
_database = None
_containedType = None

# defaults for ILocation (base of IDBContainer)
__parent__ = None
__name__ = None

def __init__( self  ):
super( DBContainer, self ).__init__( )
self.__setstate__()

def _filterKey( self, newKey ):
check that key is ascii string or unicode, and convert
to unicode.

if newKey is None:
TypeError( key can't be None )
elif isinstance( newKey, str ):
try:
newKey = unicode( newKey )
except UnicodeError:
raise TypeError(name not unicode or ascii string)

elif not isinstance( newKey, unicode ):
raise TypeError( key '%s' must be ascii or unicode string
% repr( newKey ) )

return newKey

def __setitem__( self, key, obj ):
Implements
L{cranedata.web.interfaces.IFundContainer.__setitem__}.
key = self._filterKey( key )
if not isinstance( obj, self._containedType ):
raise TypeError( object '%s' must be a %s % ( repr( obj ),
self._containedType.__name__ ) )

self._database.add( obj )
setitem( self, self.data.__setitem__, key, obj )

def __getitem__( self, key ):
return self.data[ self._filterKey( key ) ]

def __delitem__( self, key ):
obj = self.data.pop( 

[Zope3-Users] newbie design questions for UI to external data

2006-02-10 Thread Shaun Cutts
Hello,

I'm trying to write a zope3 UI for data in an RDBMS with python business
logic. (Hence updates shouldn't go directly to the database; queries are
probably best off using the marshalling code in business logic as well,
but could use direct query if its especially easy.)

I was trying to adapt Stephan Ritcher's Zope3 book examples, but am
getting a bit snarled with escaping from/interacting with the ZODB.

For a collection of objects that live in the DDBMS, should I try to
implement a collection object that itself lives in the ZODB (inherits
from Persistent, implements IContainer), but really performs a query to
get its data?

Then I need to mark actual contents volatile (?) Is there a hook to set
the volatile contents?

Also, it would be good to have a simple admin object in the ZODB that
has DB connection info. Putting one there and making it accessible via
Zope3 seems easy enough -- just inherit from Persistent But how do I
access this info from, say, my collection object(s). Does Persistent
generate a standard key?

Or should I have one big database object in ZODB that has attributes
for the connection, and also attributes for each of the collections.
This seems easy enough, but then I wonder if the zcml config will become
tricky, as I would have to declare forms for attributes of instances
(somehow)?

When using the standard forms, I got errors for not setting __name__ and
__parent__ on my contained objects. The first was easy enough, but who
is supposed to set __parent__?

I want to use standard forms if possible for the moment, as I am trying
to get up a prototype fast. Eventually I will need a paged view. Is
there one out there to use?

In general, if there is a good example of something like I am trying to
do, I would be grateful if someone could point me to it.

- Shaun Cutts


___
Zope3-users mailing list
Zope3-users@zope.org
http://mail.zope.org/mailman/listinfo/zope3-users