Hi guys,

Thanks for all the input and recommendations.

No problem about overwriting anything because all my extended methods start 
with x_*.

Same approach I follow for all my table and field definitions, all starting 
with x*, and this way I can use any name I want without any problems with 
reserved words.

With respect to the "why", it's just for convenience of executing these 
extended methods from the actual pertinent instance (using self.*).

Furthermore I believe that I finally solved my concurrency problems with the 
following approach (if anyone is interested):

+ remember to use the following to track changes (at the beginning of your 
model):

   from gluon.custom_import import track_changes
   track_changes()

+ access "current" in your model:

   now = request.now
   from gluon import current
   # assign any object(s) to current to be shared/accessed via the extended 
methods.
   current.now = now

+ do the following immediately after you define the db in your model (in 
order to access "current" via the "db" in the extended methods):

   current.db = db
   db.current = current

+ import the module to be created in your model:

   from MODULE_EXTENSIONS import *

+ implement the following as a module (not model) in order to create all the 
extensions (MODULE_EXTENSIONS.py).


=== === ===

from gluon import dal, sqlhtml
from gluon.storage import Storage

cls = Storage()
cls.db = DAL
cls.table = dal.Table
cls.field = dal.Field
cls.set = dal.Set
cls.rows = dal.Rows
cls.reference = dal.Reference
cls.row = dal.Row
cls.form = sqlhtml.SQLFORM


# in each of x_mymethods, accept args, vars, and do & return whatever is 
necessary in the *inner* methods.
# you can have any number of extended methods per class, and you can extend 
other system classes as well.
# access the environment-specific db (thread/concurrent safe, so far?) in 
each case via the comments in each of the below classes.
# access the environment-specific "current" (thread/concurrent safe, so 
far?) via (db).current.


# db ... self
class Xx_db(object):
    def x_mymethod(self):
        def _(self, *args, **kwargs):
            # do anything here with self as the actual DAL.
            return 'return any'
        return _


# db ... self._db
class Xx_table(object):
    def x_mymethod(self):
        def _(self, *args, **kwargs):
            # do anything here with self as the actual Table.
            return 'return any'
        return _


# db ... self.db
class Xx_field(object):
    def x_mymethod(self):
        def _(self, *args, **kwargs):
            # do anything here with self as the actual Field.
            return 'return any'
        return _


# db ... self.db
class Xx_set(object):
    def x_mymethod(self):
        def _(self, *args, **kwargs):
            # do anything here with self as the actual Set.
            return 'return any'
        return _


# db ... self.db
class Xx_rows(object):
    def x_mymethod(self):
        def _(self, *args, **kwargs):
            # do anything here with self as the actual Rows.
            return 'return any'
        return _


# just redirect to the respective row.
class Xx_reference(object):
    def x_self(self):
        def _(self):
            self._dummy_ # in order to force __allocate().
            return self._record
        return _
    # redirect all necessary methods to the row object.
    def x_mymethod(self):
        def _(self, *args, **kwargs):
            return self.x_self().x_mymethod(*args, **kwargs)
        return _


# for Row, you can assign the following virutal field in your model
# in order to directly access the db:
#     def db(self): return db
# db ... self.db
class Xx_row(object):
    def x_mymethod(self):
        def _(self, *args, **kwargs):
            # do anything here with self as the actual Row.
            return 'return any'
        return _


# db ... self.table._db
class Xx_form(object):
    def x_mymethod(self):
        def _(self, *args, **kwargs):
            # do anything here with self as the actual SQLFORM.
            return 'return any'
        return _


# do all the magic to extend the above classes with the respective methods.
def doXx():
    prefix = 'Xx_'
    xclasses = [ v for (k, v) in globals().items() if k.startswith(prefix) ]
    # print 'doXx > xclasses', xclasses
    for xclass in xclasses:
        source = xclass()
        xclassname = xclass.__name__
        target = cls.get(xclassname[len(prefix):])
        props = [ prop for prop in dir(source) if not prop.startswith('__') 
]
        for prop in props:
            method = getattr(source, prop)
            if hasattr(method, 'im_func') and 
method.im_func.func_code.co_argcount == 1:
                # print 'doXx > method', method
                setattr(target, prop, method())
                # necessary to do the following?
                '''
                newmethod = getattr(target, prop)
                f = newmethod.__func__
                f.__name__ = method.__name__
                '''
            else:
                msg = 'ERROR ... doXx - INVALID METHOD: %s > %s' % 
(xclassname, prop)
                print msg

# execute the magic.
doXx()

print 'END'

=== === ===

(not sure if I missed something, because I had to extract this code from my 
project)

So far this is working for me, but Massimo and others have the final word.

Thanks and take care,

   Carlos

Reply via email to