Author: luke
Date: 2007-04-15 17:25:54 -0600 (Sun, 15 Apr 2007)
New Revision: 2537
Modified:
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_dependency.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_dependency_manager.py
SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_materialized.py
Log:
Updates to materialized/dependency handling
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency.py 2007-04-15 22:27:53 UTC (rev 2536)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/dependency.py 2007-04-15 23:25:54 UTC (rev 2537)
@@ -1,8 +1,11 @@
from sqlobject import declarative
+from sqlobject import sqlbuilder
from sqlobject.events import *
from sqlobject.include.pydispatch import dispatcher
+from sqlobject import classregistry
from operator import isCallable
+import inspect
def _processDependentOn(new_class_name, bases, new_attrs, post_funcs, early_funcs):
def f(cls):
@@ -20,17 +23,17 @@
class DependencyItem(object):
- def __init__(self, item):
+ def __init__(self, item, *extras):
self.key = item
- self.value = item
+ self.value = item + extras
class Dependency(object):
DependencyItemClass = DependencyItem
DecoratorFactory = depFromClsAttr
- def __init__(self, target, source, **extra):
- self.target = self.DependencyItemClass(target)
- self.source = self.DependencyItemClass(source)
+ def __init__(self, target, source, *extras):
+ self.target = self.DependencyItemClass(target, *extras)
+ self.source = self.DependencyItemClass(source, *extras)
class DependencyManager(object):
DependencyClass = Dependency
@@ -45,7 +48,7 @@
self._deps.setdefault(dep.source.key, set()).add(dep.target)
self._reverseDeps.setdefault(dep.target.key, set()).add(dep.source)
- def get(self, source):
+ def get(self, *source):
''' get immediate dependent values for source '''
return self.getMany([source])
@@ -71,8 +74,9 @@
for target in deps.get(source,set())))
- def dependentOn(self, source, factory=None):
+ def dependentOn(self, *source, **kw):
''' decorator '''
+ factory = kw.pop('factory', None)
if factory is None:
factory = self.DependencyClass.DecoratorFactory()
def decorate(func):
@@ -86,10 +90,8 @@
def dependencyForAdd(self, *args):
if len(args) == 1 and isinstance(args[0], self.DependencyClass):
dep = args[0]
- elif len(args) == 2:
+ else:
dep = self.DependencyClass(*args)
- else:
- raise TypeError('Incorrect arguments to add(), expected %s instance or (target,source), got: %s' % (self.DependencyClass.__name__, args))
return dep
#if isinstance(inst, str):
@@ -97,20 +99,57 @@
#else:
# sourceClass = inst.__class__.__name__
+
class SQLDependency(Dependency):
- pass
+ def __init__(self, target, source, *extras):
+ if isinstance(source[0], sqlbuilder.SQLExpression):
+ source = (str(source[0].tableName), str(source[0].fieldName)) + source[1:]
+ print source
+ if len(source) == 3:
+ other = source[2]
+ try:
+ hash(other)
+ except TypeError:
+ other = lambda o=other: o
+ extras = (other,) + extras
+ source = source[:2]
+ else:
+ extras = (None,) + extras
+ self.target = self.DependencyItemClass(target, *extras)
+ self.source = self.DependencyItemClass(source, *extras)
class SQLDependencyManager(DependencyManager):
+ DependencyClass = SQLDependency
- def process(self, inst, attrs):
- ''' find and recalculate items dependent on attrs'''
+ def instancesToProcess(self, inst, attrs):
+ ''' find items dependent on attrs'''
+ ret = {}
sourceClass = inst.__class__.__name__
deps = self.getMany((sourceClass, attr) for attr in attrs)
- for targetClass, targetAttr, route in deps:
- targetClass = getClassFromName(targetClass)
- for t_inst in route(inst, targetClass):
- t_inst._SO_resetCache(targetAttr)
+ for targetClassName, targetAttr, route in deps:
+
+ targetClass = classregistry.findClass(targetClassName, class_registry=inst.sqlmeta.registry)
+
+ print "Route", route
+ if inspect.isfunction(route):
+ argspec = inspect.getargspec(route)
+ print "argspec", argspec
+ if len(argspec[0]) == len(argspec[3]) and not argspec[1] and not argspec[2]:
+ print "exec", route()
+ route = route()
+ print "RouteX", route
+ if route is None:
+ route = lambda i,c: [i]
+ elif isinstance(route, sqlbuilder.SQLExpression):
+ route = lambda i,c,r=route: c.select(sqlbuilder.AND(r, i))
+
+ ret.setdefault((targetClassName, targetAttr),[]).extend(route(inst, targetClass))
+ return ret
+ def process(self, inst, attrs):
+ for (cls, attr), insts in self.instancesToProcess(inst, attrs).iteritems():
+ for inst in insts:
+ inst._SO_resetCache(attr)
def FK(self, name):
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized.py 2007-04-15 22:27:53 UTC (rev 2536)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/materialized.py 2007-04-15 23:25:54 UTC (rev 2537)
@@ -10,14 +10,14 @@
def _addColumn(cls, connection, column_name, column_definition, changeSchema, post_funcs):
def f(cls, col):
if col.foreignKey:
- dep.add((cls.__name__, col.name), (col.foreignKey, 'id'))
+ dep.add((cls.__name__, col.name), (col.foreignKey, 'id', lambda cls=cls,col=col: getattr(cls.q, col.origName)))
post_funcs.append(f)
events.listen(_addColumn, MaterializedSQLObject, events.AddColumnSignal)
def _addJoin(cls, join_name, join_definition, post_funcs):
def f(cls, join):
- dep.add((cls.__name__, join.joinMethodName), (join.otherClassName, 'id'))
+ dep.add((cls.__name__, join.joinMethodName), (join.otherClassName, 'id', lambda cls=cls,join=join: getattr(cls.q, join.joinMethodName)))
post_funcs.append(f)
events.listen(_addJoin, MaterializedSQLObject, events.AddJoinSignal)
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_dependency.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_dependency.py 2007-04-15 22:27:53 UTC (rev 2536)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_dependency.py 2007-04-15 23:25:54 UTC (rev 2537)
@@ -3,16 +3,17 @@
from sqlobject.tests.dbtest import *
from sqlobject.materialized import *
+dep = DependencyManager()
class DependencyOne(SQLObject):
name = StringCol()
twos = SQLMultipleJoin('DependencyTwo', joinColumn='one_id')
- @dep.dependentOn(('DependencyOne', 'twos'))
+ @dep.dependentOn('DependencyOne', 'twos')
def _get_twoCount(self):
return self.twos.count()
- @dep.dependentOn(('DependencyTwo', 'length'))
+ @dep.dependentOn('DependencyTwo', 'length')
def _get_detailSize(self):
return self.twos.sum('length')
@@ -21,12 +22,12 @@
length = IntCol()
one = ForeignKey('DependencyOne')
- @dep.dependentOn(('DependencyOne', 'name'))
+ @dep.dependentOn('DependencyOne', 'name')
def _get_name(self):
return self.one.name
- @dep.dependentOn(('DependencyTwo', 'detail'))
- @dep.dependentOn(('DependencyOne', 'name'))
+ @dep.dependentOn('DependencyTwo', 'detail')
+ @dep.dependentOn('DependencyOne', 'name')
def _get_name2(self):
return self.one.name + self.detail
@@ -34,5 +35,5 @@
setupClass([DependencyOne, DependencyTwo])
def testSetup():
- assert dep.get(('DependencyOne', 'name')) == set([('DependencyTwo','_get_name'),
+ assert dep.get('DependencyOne', 'name') == set([('DependencyTwo','_get_name'),
('DependencyTwo','_get_name2')])
\ No newline at end of file
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_dependency_manager.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_dependency_manager.py 2007-04-15 22:27:53 UTC (rev 2536)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_dependency_manager.py 2007-04-15 23:25:54 UTC (rev 2537)
@@ -25,13 +25,13 @@
def test_addDependency():
dep = DependencyManager()
dep.add(('B', 'name'), ('A', 'name'))
- assert dep.get(('A', 'name')) == set([('B', 'name')])
+ assert dep.get('A', 'name') == set([('B', 'name')])
def test_addDependencies():
dep = DependencyManager()
dep.add(('B', 'name'), ('A', 'name'))
dep.add(('B', 'condName'), ('A', 'name'))
- assert dep.get(('A', 'name')) == set((('B', 'name'),
+ assert dep.get('A', 'name') == set((('B', 'name'),
('B', 'condName')))
def test_addDepWithDecorator():
@@ -41,11 +41,11 @@
a = A()
- @dep.dependentOn(('A', 'name'))
+ @dep.dependentOn('A', 'name')
def name(self):
return self.a.name
- assert dep.get(('A', 'name')) == set([('C', 'name')])
+ assert dep.get('A', 'name') == set([('C', 'name')])
def test_addDepsWithDecorator():
dep = DependencyManager()
@@ -55,13 +55,13 @@
a = A()
b = B()
- @dep.dependentOn(('B', 'name'))
- @dep.dependentOn(('A', 'name'))
+ @dep.dependentOn('B', 'name')
+ @dep.dependentOn('A', 'name')
def name(self):
return self.a.name + self.b.name
- assert dep.get(('A', 'name')) == set([('C', 'name')])
- assert dep.get(('B', 'name')) == set([('C', 'name')])
+ assert dep.get('A', 'name') == set([('C', 'name')])
+ assert dep.get('B', 'name') == set([('C', 'name')])
@@ -122,7 +122,7 @@
('c','x'): (('x', 2), {})
}
- assert dep.get(('a','w')) == set([('x', 1), ('x', 2)])
+ assert dep.get('a','w') == set([('x', 1), ('x', 2)])
#def test_addDepWithSignal():
Modified: SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_materialized.py
===================================================================
--- SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_materialized.py 2007-04-15 22:27:53 UTC (rev 2536)
+++ SQLObject/branches/cache-deps-on-views/sqlobject/materialized/tests/test_materialized.py 2007-04-15 23:25:54 UTC (rev 2537)
@@ -2,18 +2,23 @@
from sqlobject import *
from sqlobject.tests.dbtest import *
from sqlobject.materialized import *
+from sqlobject.sqlbuilder import ImportProxy
+MO = ImportProxy('MaterializedOne')
+MT = ImportProxy('MaterializedTwo')
+
+
class MaterializedOne(MaterializedSQLObject):
name = StringCol()
twos = SQLMultipleJoin('MaterializedTwo', joinColumn='one_id')
@cachedAs(IntCol)
- @dep.dependentOn(('MaterializedOne', 'twos'))
+ @dep.dependentOn('MaterializedOne', 'twos', MO.q.twos)
def _get_twoCount(self):
return self.twos.count()
@cachedAs(IntCol)
- @dep.dependentOn(('MaterializedTwo', 'length'))
+ @dep.dependentOn('MaterializedTwo', 'length', MO.q.twos)
def _get_detailSize(self):
return self.twos.sum('length')
@@ -23,27 +28,48 @@
one = ForeignKey('MaterializedOne')
@cachedAs(StringCol)
- @dep.dependentOn(('MaterializedOne', 'name'))
+ @dep.dependentOn('MaterializedOne', 'name', MT.q.one)
def _get_name(self):
return self.one.name
@cachedAs(StringCol)
- @dep.dependentOn(('MaterializedTwo', 'detail'))
- @dep.dependentOn(('MaterializedOne', 'name'))
+ @dep.dependentOn('MaterializedTwo', 'detail')
+ @dep.dependentOn('MaterializedOne', 'name', MT.q.one)
def _get_name2(self):
return self.one.name + self.detail
def setup_module(mod):
setupClass([MaterializedOne, MaterializedTwo])
+ mod.ones = inserts(MaterializedOne, (('S',),
+ ('T',),
+ ), 'name')
+ mod.twos = inserts(MaterializedTwo, (('a', 2, mod.ones[0].id),
+ ('b', 3, mod.ones[0].id),
+ ('c', 4, mod.ones[1].id),
+ ('d', 5, mod.ones[1].id),
+ ), 'detail length oneID')
def testSetup():
- assert dep.get(('MaterializedOne', 'name')) == set([('MaterializedTwo','_get_name'),
- ('MaterializedTwo','_get_name2')])
+ deps = dep.get('MaterializedOne', 'name')
+ assert set([(x,y) for x,y,z in deps]) == set([('MaterializedTwo','_get_name'),
+ ('MaterializedTwo','_get_name2')])
+ assert [z for x,y,z in deps][0] != [None, None]
def testSetupDepsForFK():
- assert dep.get(('MaterializedOne', 'id')) == set([('MaterializedTwo', 'oneID')])
+ # Can't test route directly
+ deps = dep.get('MaterializedOne', 'id')
+ assert [(x,y) for x,y,z in deps][0] == ('MaterializedTwo', 'oneID')
+ assert [z for x,y,z in deps][0] is not None
def testSetupDepsForJoin():
- assert dep.get(('MaterializedTwo', 'id')) == set([('MaterializedOne', 'twos')])
+ deps = dep.get('MaterializedTwo', 'id')
+ assert set((x,y) for x,y,z in deps) == set([('MaterializedOne', 'twos')])
+ assert [z for x,y,z in deps][0] is not None
-
\ No newline at end of file
+
+def testProcessInstances():
+
+ assert dep.instancesToProcess(ones[0], ['name']) == {
+ ('MaterializedTwo', '_get_name'): [twos[0], twos[1]],
+ ('MaterializedTwo', '_get_name2'): [twos[0], twos[1]],
+ }
\ No newline at end of file
|