traits inherited package strategy

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

traits inherited package strategy

Fabio Pliger
Hi all,

I'm willing to release a package that is a sort of a revision of many "playground sessions" I've made with Traits in the last years. I'd like to check with you guys if you do think that the approach I've used is ok or you have any hints or concerns about it.

This package purpose is auto generative guis and applications from SQLAlchemy "like" ORM classes. ( the package name preference at the moment is alchemyui :) ). For doing this I use Traits for class tables mapping and columns type convertion ( to traits types ) and derived automatic gui generation. This aims to help both newbies and advanced developers that have to spend lots of time in boilerplate code for GUI generation. I know there was a project around enthought packages that aimed to achieve similar results but I think it's a little bit different...

I've tried to keep the package usage very lean and simple. Deriving from this principle the package usage is around 2 main methods: one for single instances management ( adding and editing existing database elements ) and another for multiple instances management ( a table with all the instances of a class available in the database, powered with some filtering tools ) that can have user defined functions called after button clicks. To generate application interfaces all you have to do is call one of those methods to "prepare" objects and then actually "call" the user interfaces.

The main issue about gluing traits and SQLAlchemy is that both use a lot of *magic* to make cool things happen. So generating code dynamicly using metaclasses was a real nightmare in the past ( when I first tried playing with this many months ago ). The easy and dirty approach I've decided to adopt in order to leave both traits and SQLAlchemy untouched was to:
- receive a simple sqlalchemy mapped ORM class
- parse its table and columns
- generate a configure method and a "container" attribute to the class. This container attribure is an instance of HasTraits class with all the table columns converted to their related Traits types

Every call to configure method calls the container "configure_traits" method to use it's generative gui visualization. You can take a look at a code sample of the package usage interface below ( although its not definitive it should give a quite good idea on how the package works ). 

So, question one: Anyone of you guys that knows all bits about traits see any waybacks in this code architecture? 

My second discussion issues is the containers dynamic generation. To achieve this I've used the simple source code generation and execution with exec( code, locals(), globals() ) ... I know this sucks, but every effort I've made in the past to do it traits and metaclasses finished failing. Any idea on this topic?

thanks in advance for any feedback 

--
Fabio Pliger

#### CODE SAMPLE ####

import alchemyui as aui  # Import of the alchemyui library
# *** SAMPLE CODE TAKEN FROM SQLAlchemy documentation
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, create_engine
from sqlalchemy.orm import sessionmaker, relationship, backref

from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:', echo=True )
metadata = MetaData(engine)
Base = declarative_base(metadata=metadata)

class User(Base):
    __tablename__ = 'users'
    
    id = Column( Integer, primary_key=True )
    name = Column( String )
    fullname = Column( String )
    password = Column( String )
    
    def __init__(self, name, fullname, password):
        self.name = name
        self.fullname = fullname
        self.password = password
        
    def __repr__(self):
        return u"<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password )
    
class Address(Base):
    __tablename__ = 'addresses'
    id = Column(Integer, primary_key=True)
    email_address = Column(String, nullable=False)
    user_id = Column(Integer, ForeignKey('users.id'))

    user = relationship(User, backref=backref('addresses', order_by=id))

    def __init__(self, email_address = None ):
        self.email_address = email_address

    def __repr__(self):
        return "<Address('%s')>" % self.email_address
    
User.metadata.create_all()
User = aui.touch( User, engine ) 
Address = aui.touch( Address, engine )
Session = sessionmaker(bind=engine)
session = Session()
# *** END OF SAMPLE CODE TAKEN FROM SQLAlchemy documentation

ed_user = User('ed', 'Ed Jones', 'edspassword')
ad_user = User('ad', 'Ad Gonzalez', 'adspassword')
ed_user.sync("TO")
session.add(ed_user)
session.add(ad_user)
session.commit()

# ed_user.configure() # We can call configure on ed_user to edit it's fields

# Now we create a new address and call configure to ask the user to add it's fields
addr = Address()
addr.configure()

def add_user( self, evt = None ):
    new_user = User()
    new_user.configure()
    new_session = Session()
    new_session.add( new_user )
    new_session.commit()
    
def say_hi( self, *args, **kws ):
    print "HI FOLKS!"
    
# Let's define some actions functions
buttons = { 
    "add" : { "label" : "add user", "handler":add_user },
    "say_hi" : { "label": "Say hi!", "handler":say_hi, "tooltip":"Please click to say hi!", }
}

# Now we generate an Frame with a list of all the users available in the database
app = aui.simple_app( User, engine, buttons ) 
app.start()


_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: traits inherited package strategy

Chris Colbert
Here's a simple way to dynamically build a traits class without using exec (add whatever functionality you need to the cls_dict):

In [1]: from enthought.traits.api import HasTraits, MetaHasTraits, Float

In [2]: cls_dict = {}

In [3]: cls_dict['a'] = Float

In [4]: Foo = MetaHasTraits('Foo', (HasTraits,), cls_dict)

In [5]: f = Foo()

In [6]: f.a
Out[6]: 0.0



On Sun, Mar 13, 2011 at 7:54 AM, Fabio Pliger <[hidden email]> wrote:
Hi all,

I'm willing to release a package that is a sort of a revision of many "playground sessions" I've made with Traits in the last years. I'd like to check with you guys if you do think that the approach I've used is ok or you have any hints or concerns about it.

This package purpose is auto generative guis and applications from SQLAlchemy "like" ORM classes. ( the package name preference at the moment is alchemyui :) ). For doing this I use Traits for class tables mapping and columns type convertion ( to traits types ) and derived automatic gui generation. This aims to help both newbies and advanced developers that have to spend lots of time in boilerplate code for GUI generation. I know there was a project around enthought packages that aimed to achieve similar results but I think it's a little bit different...

I've tried to keep the package usage very lean and simple. Deriving from this principle the package usage is around 2 main methods: one for single instances management ( adding and editing existing database elements ) and another for multiple instances management ( a table with all the instances of a class available in the database, powered with some filtering tools ) that can have user defined functions called after button clicks. To generate application interfaces all you have to do is call one of those methods to "prepare" objects and then actually "call" the user interfaces.

The main issue about gluing traits and SQLAlchemy is that both use a lot of *magic* to make cool things happen. So generating code dynamicly using metaclasses was a real nightmare in the past ( when I first tried playing with this many months ago ). The easy and dirty approach I've decided to adopt in order to leave both traits and SQLAlchemy untouched was to:
- receive a simple sqlalchemy mapped ORM class
- parse its table and columns
- generate a configure method and a "container" attribute to the class. This container attribure is an instance of HasTraits class with all the table columns converted to their related Traits types

Every call to configure method calls the container "configure_traits" method to use it's generative gui visualization. You can take a look at a code sample of the package usage interface below ( although its not definitive it should give a quite good idea on how the package works ). 

So, question one: Anyone of you guys that knows all bits about traits see any waybacks in this code architecture? 

My second discussion issues is the containers dynamic generation. To achieve this I've used the simple source code generation and execution with exec( code, locals(), globals() ) ... I know this sucks, but every effort I've made in the past to do it traits and metaclasses finished failing. Any idea on this topic?

thanks in advance for any feedback 

--
Fabio Pliger

#### CODE SAMPLE ####

import alchemyui as aui  # Import of the alchemyui library
# *** SAMPLE CODE TAKEN FROM SQLAlchemy documentation
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, create_engine
from sqlalchemy.orm import sessionmaker, relationship, backref

from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:', echo=True )
metadata = MetaData(engine)
Base = declarative_base(metadata=metadata)

class User(Base):
    __tablename__ = 'users'
    
    id = Column( Integer, primary_key=True )
    name = Column( String )
    fullname = Column( String )
    password = Column( String )
    
    def __init__(self, name, fullname, password):
        self.name = name
        self.fullname = fullname
        self.password = password
        
    def __repr__(self):
        return u"<User('%s','%s', '%s')>" % (self.name, self.fullname, self.password )
    
class Address(Base):
    __tablename__ = 'addresses'
    id = Column(Integer, primary_key=True)
    email_address = Column(String, nullable=False)
    user_id = Column(Integer, ForeignKey('users.id'))

    user = relationship(User, backref=backref('addresses', order_by=id))

    def __init__(self, email_address = None ):
        self.email_address = email_address

    def __repr__(self):
        return "<Address('%s')>" % self.email_address
    
User.metadata.create_all()
User = aui.touch( User, engine ) 
Address = aui.touch( Address, engine )
Session = sessionmaker(bind=engine)
session = Session()
# *** END OF SAMPLE CODE TAKEN FROM SQLAlchemy documentation

ed_user = User('ed', 'Ed Jones', 'edspassword')
ad_user = User('ad', 'Ad Gonzalez', 'adspassword')
ed_user.sync("TO")
session.add(ed_user)
session.add(ad_user)
session.commit()

# ed_user.configure() # We can call configure on ed_user to edit it's fields

# Now we create a new address and call configure to ask the user to add it's fields
addr = Address()
addr.configure()

def add_user( self, evt = None ):
    new_user = User()
    new_user.configure()
    new_session = Session()
    new_session.add( new_user )
    new_session.commit()
    
def say_hi( self, *args, **kws ):
    print "HI FOLKS!"
    
# Let's define some actions functions
buttons = { 
    "add" : { "label" : "add user", "handler":add_user },
    "say_hi" : { "label": "Say hi!", "handler":say_hi, "tooltip":"Please click to say hi!", }
}

# Now we generate an Frame with a list of all the users available in the database
app = aui.simple_app( User, engine, buttons ) 
app.start()


_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev



_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev
Reply | Threaded
Open this post in threaded view
|

Re: traits inherited package strategy

Fabio Pliger

2011/3/14 Chris Colbert <[hidden email]>
Here's a simple way to dynamically build a traits class without using exec (add whatever functionality you need to the cls_dict):

In [1]: from enthought.traits.api import HasTraits, MetaHasTraits, Float

In [2]: cls_dict = {}

In [3]: cls_dict['a'] = Float

In [4]: Foo = MetaHasTraits('Foo', (HasTraits,), cls_dict)

In [5]: f = Foo()

In [6]: f.a
Out[6]: 0.0

Great!! Thanks very much for hint Chris, much more nice and elegant. 

cheers

--
Fabio Pliger


_______________________________________________
Enthought-Dev mailing list
[hidden email]
https://mail.enthought.com/mailman/listinfo/enthought-dev