Roadmap to Active Record pattern

26 views
Skip to first unread message

Cédric Krier

unread,
Mar 22, 2010, 11:15:00 AM3/22/10
to tryton
Hi,

I think it will be good for Tryton to try to get closer to the Active Record
pattern [1].

So here are some steps to achieve this goal:

cursor, user and context
------------------------

They should be removed from the function call and be shared across the code by
thread.
I propose to create an object trytond.transaction that will be handle those
thread-local data [2]. It will be filled by the trytond.protocols.dispatcher
for each remote call. It should also be able to save current data in a stack
and restore it later because in some part of the code we need to perform some
actions with the rights of an other user or execute some database queries in a
different transaction. It should also ensure that the stack have been "poped"
before the end of the transaction.

To be able to fill the transaction object with the context, the RPC signature
call should be changed to know which argument is the context.

Pool
----

The pool should be retrieve from the transaction object instead of beeing
liked to the models. This will ensure that the database on which the cursor is
connected is the same then the one define for the Pool. And it will also allow
to have fields named "pool".

Model
-----

We should stop working with Model instance in the Pool but use only classes.
So the current function like "create", "write", "search", "browse" etc. that
take almost all ids as argument should become classmethods and browse will
return an instance of the Model instead of the BrowseRecord.
Of course, we should keep the cache management from the BrowseRecord and the
way we read data for many ids at once to keep good performance.

This will allow to change the setter, getter function that will work on the
"BrowseRecord" (that will be a Model instance) instead of working on ids.

Button function will also become classmethods.

And a new function will be available on Model instance named "store" that will
perform the write of changes in the database.

The __init__ way of changing Model will be replace by metaclass programming
[3].

Extension
---------

This is the part that I don't see well how we could make it more pythonic.
For now, the mechanism is:

- we store Model instances in a dict (Pool) by their name
- if there is already a Model class with the same name, we make the new one
inherit (in the python way) from the old one. And replace the old by the
new one.

So Tryton extension is based on "on the fly" inheritage. The pool constructs a
new object from the module installed for a database. This can be viewed like
decorators or monkey patching [4].

I don't know yet which method will be the best one.

But I'm pretty sure that we must stop faking instanciation of the Models (in
fact it register it in the Pool) and using directly the method
Pool.register(klass, ...)

Planning
--------

All those changes can not be done of course for the 1.6 release but I think it
is possible for 1.8. Each steps describe here can be done one by one and
keeping the software working. But of course it will require some modifications
for the modules. But I think if we use well-know patterns like Active Record,
it will reduce the learning curve of programming in Tryton.

Others
------

I often see people asking (on OpenERP) why not using SQLAchemy [5] especially
for the pythonic syntax of query. I think we should keep the current domain
syntax that uses only simple objects (list, string, tuple) because it allow to
expose it to the RPC protocols without too much difficulty because all common
languages have this simple objects. But it could be extended to allow
aggregation, field to field operations etc.


So comments are welcome, especially on the "Extension" part.
I will write a blue print shortly.


[1] http://en.wikipedia.org/wiki/Active_record
[2] http://docs.python.org/library/threading.html#threading.local
[3] http://docs.python.org/reference/datamodel.html#customizing-class-creation
[4] http://en.wikipedia.org/wiki/Monkey_patch
[5] http://www.sqlalchemy.org/

--
Cédric Krier

B2CK SPRL
Rue de Rotterdam, 4
4000 Liège
Belgium
Tel: +32 472 54 46 59
Email/Jabber: cedric...@b2ck.com
Website: http://www.b2ck.com/

Sharoon Thomas

unread,
Mar 22, 2010, 12:09:56 PM3/22/10
to tryto...@googlegroups.com
These ideas are really good and will make Tryton more pythonic.

Regarding Model:

If metaclass programming is used and each record becomes an instance of the class representing the model, then the methods of the class becomes methods/functions/properties acting on individual instances (or records) and not the object as a whole.

  • So how is the extension of modules planned ?

For example:

a current pool.get(object).write(...) can no longer exist but a write will be method of the instance.

So if productcategory1 = ProductCategory(<values>) then the write method will be an instance method therefore productcategory1.write(<values>)

  • Can we use args/kwargs based initiation
I think the metaclass programming should give us the advantage of creating instance objects from kwargs. For example new_category = ProductCategory(name="Computers", code="COMP")

  • Can inheritance of models also be pythonic?
Instead of using _inherit = '' can we directly use python inheritance. For example, if we have to extend product category then:

from trytond.modules.product.category import ProductCategory

class NewProductCategory(ProductCategory):
   def get_full_name(self):
         return self.parent_name + "/" + self.name 

Sharoon Thomas
Business Analyst & ERP Consultant
Open Labs Business Solutions

On Mon, Mar 22, 2010 at 3:15 PM, Cédric Krier <cedric...@b2ck.com> wrote:
Hi,

I think it will be good for TrytoI n to try to get closer to the Active Record

Cédric Krier

unread,
Mar 22, 2010, 5:48:10 PM3/22/10
to tryto...@googlegroups.com
On 22/03/10 16:09 +0000, Sharoon Thomas wrote:
> These ideas are really good and will make Tryton more pythonic.
>
> Regarding Model:
>
> If metaclass programming is used and each record becomes an instance of the
> class representing the model, then the methods of the class becomes
> methods/functions/properties acting on individual instances (or records) and
> not the object as a whole.
>
>
> - So how is the extension of modules planned ?

I don't understand.

>
>
> For example:
>
> a current pool.get(object).write(...) can no longer exist but a write will
> be method of the instance.

This will still exist but pool.get('object') will return a class and no more
an instance.

>
> So if productcategory1 = ProductCategory(<values>) then the write method
> will be an instance method therefore productcategory1.write(<values>)
>
>

> - Can we use args/kwargs based initiation

Why not. But we should keep current dictionary values for rpc calls.

>
> I think the metaclass programming should give us the advantage of creating
> instance objects from kwargs. For example new_category =
> ProductCategory(name="Computers", code="COMP")
>
>

> - Can inheritance of models also be pythonic?


>
> Instead of using _inherit = '' can we directly use python inheritance. For

There is no _inherit in Tryton.

> example, if we have to extend product category then:
>
> from trytond.modules.product.category import ProductCategory
>
> class NewProductCategory(ProductCategory):
> def get_full_name(self):
> return self.parent_name + "/" + self.name

This is not possible but we should try a way to improve the current
implementation.

Cédric Krier

unread,
Mar 25, 2010, 8:59:50 AM3/25/10
to tryton
After a talk with Sharoon, here is the new ideas:

To be able to have metaclass programming able to handle current extention
behavior, we require to have one database per process. Because metaclass will
be called only once after that Python will store the result and a model must
have a class per database.
So the goal is to have a handler process that will dispatch queries to
children depending of the database. We could use multiprocessing module that
is available since 2.6.

This idea brings an other one where we could have also one process per
protocols. And perhaps have one process per netrpc connection as it is a
stateful connection.

Chenal Bertrand

unread,
Mar 25, 2010, 10:25:00 AM3/25/10
to tryto...@googlegroups.com
Le 25/03/10 13:59, C�dric Krier a �crit :

> After a talk with Sharoon, here is the new ideas:
>
> To be able to have metaclass programming able to handle current extention
> behavior, we require to have one database per process. Because metaclass will
> be called only once after that Python will store the result and a model must
> have a class per database.
> So the goal is to have a handler process that will dispatch queries to
> children depending of the database. We could use multiprocessing module that
> is available since 2.6.
>
The processing module is also available for python 2.4 and 2.5 (but not
in the standard library).

> This idea brings an other one where we could have also one process per
> protocols. And perhaps have one process per netrpc connection as it is a
> stateful connection.
>
>


--
Bertrand Chenal

B2CK SPRL
Rue de Rotterdam, 4

4000 Li�ge
Belgium
Tel: +32 474 207 906
Email: bertran...@b2ck.com
Website: http://www.b2ck.com/

Reply all
Reply to author
Forward
0 new messages