In answer to my own question -- YES, I was missing a few things.
1. The implementation of "hasattr" itself calls the _getattr_ and looks
for the exception. It is working as expected. There is no "hasattr"
problem.
2. The table that is failing is called "club". When it gets its turn to
be defined, it is happily added to the _LAZY_TABLES list. I put a watch on
that list to see when it goes away.
3. The lazy version of "club" is removed later when another table
definition looks for "reference club". In that lookup, the _getattr_
routine falls through to the point where lazy_define_table is called.
4. Looking at the code, this call is happening in a "chain" of
lazy_define_table calls -- all are happening because a lazy table is
referenced by another table. The reference when it is looked up
instantiates the table.
5. But! The _getattr_ call to lazy_define_table does *not add the
newly-instantiated table to the list of actual tables in the DAL*. So at
this point, the lazy table has been removed from the _LAZY_TABLES list and
instantiated, but the resulting structure was thrown away instead of being
saved in the DAL.
def __getattr__(self, key):
if ogetattr(self,'_lazy_tables') and \
key in ogetattr(self,'_LAZY_TABLES'):
tablename, fields, args = self._LAZY_TABLES.pop(key)
return self.lazy_define_table(tablename,*fields,**args)
return ogetattr(self, key)
As a possible remedy, I took the following two lines from "define_table"
and put them at the end of "lazy_define_table":
if not tablename in self.tables:
self.tables.append(tablename)
This ensures that the table structure is not thrown away when the table
name is probed as an attribute of the DAL, causing the table to be
instantiated. It fixes my code and makes the lazy tables work properly in
my context.
My fix might have a negative effect on the time savings, however. It may
be better to re-work the logic so that a reference to a table does not need
to cause it to be built.
--