diff -Nru metamodel-0.1.1/debian/changelog metamodel-0.1.2/debian/changelog --- metamodel-0.1.1/debian/changelog 2009-12-02 17:55:46.000000000 +0000 +++ metamodel-0.1.2/debian/changelog 2009-12-09 13:50:55.000000000 +0000 @@ -1,3 +1,9 @@ +metamodel (0.1.2-1karmic1) karmic; urgency=low + + * New Upstream Version + + -- Pablo Martin (caedes) Wed, 09 Dec 2009 14:50:43 +0100 + metamodel (0.1.1-3karmic1) karmic; urgency=low * Build for karmic diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/debian/control /tmp/dmMTQQlFD1/metamodel-0.1.2/debian/control --- metamodel-0.1.1/debian/control 2009-12-02 17:53:44.000000000 +0000 +++ metamodel-0.1.2/debian/control 2009-12-09 13:52:51.000000000 +0000 @@ -1,5 +1,5 @@ Source: metamodel -Section: python +Section: python Priority: extra Maintainer: Angel Abad (Ikusnet SLL) Build-Depends: debhelper (>= 7), python, python-setuptools @@ -10,7 +10,7 @@ Package: python-metamodel Architecture: all Depends: ${misc:Depends}, ${python:Depends}, python-yaml -Suggest: python-twisted-core, python-feedparser, python-svn +Suggest: python-twisted-core, python-feedparser, python-svn, python-twisted-web Provides: ${python:Provides} Description: Unified Metamodel based model library Model package for Python offering automatic serialization and diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/docs/restapi.txt /tmp/dmMTQQlFD1/metamodel-0.1.2/docs/restapi.txt --- metamodel-0.1.1/docs/restapi.txt 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/docs/restapi.txt 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,16 @@ +/schema/ +GET: get class info for instance of given path + +/[/] +GET: get instance list for given classname + +/classes/ +GET: get class info, or child info + +/ +GET: get instance or children if ends with "/" +POST: post a new object (sent to a "/" path) +PUT: update object properties +DELETE: delete given object + + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/examples/testcclient.py /tmp/dmMTQQlFD1/metamodel-0.1.2/examples/testcclient.py --- metamodel-0.1.1/examples/testcclient.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/examples/testcclient.py 2009-12-09 13:50:29.000000000 +0000 @@ -0,0 +1,15 @@ +from twisted.internet import reactor +from metamodel.datasources.twistedmm.client import MMClientDataSource +from metamodel import SubscribableModel + +class MyClient(MMClientDataSource): + def clientConnected(self): + self.addChild(self.new(SubscribableModel)) + +client = MyClient() +client.port = 10113 +client.server = 'localhost' +client.active = True +reactor.run() + + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/examples/testclient.py /tmp/dmMTQQlFD1/metamodel-0.1.2/examples/testclient.py --- metamodel-0.1.1/examples/testclient.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/examples/testclient.py 2009-12-09 13:50:29.000000000 +0000 @@ -0,0 +1,22 @@ +from twisted.internet import reactor +from metamodel.datasources.twistedmm.client import MMClientDataSource +from metamodel import SubscribableModel + +def print_model(model, spaces=1): + print " "*spaces,"* "+model.name,"("+model.__class__.__name__+")" + for child in model.getChildren(): + print_model(child, spaces+1) + + +class MyClient(MMClientDataSource): + def clientConnected(self): + root = self.getChildren()[0] + print "DATA:" + print_model(self) + +client = MyClient() +client.port = 10110 +client.server = '10.66.66.69' +client.active = True +reactor.run() + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/examples/testrestserver.py /tmp/dmMTQQlFD1/metamodel-0.1.2/examples/testrestserver.py --- metamodel-0.1.1/examples/testrestserver.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/examples/testrestserver.py 2009-12-09 13:50:29.000000000 +0000 @@ -0,0 +1,55 @@ +from twisted.internet import reactor +from metamodel.datasources.twistedmm.server import MMServerDataSource +from metamodel.datasources.filesource import FileDataSource +from metamodel.datasources.restserver import MMRestServer +from metamodel.datasources.rsssource import RSSDataSource +#from metamodel.datasources.twistedmm.client import MMClientDataSource + +from metamodel import SubscribableModel as Model +from metamodel import Property + + +class TestClass(Model): + name = Property(str, 'name') + testprop = Property(str, '') + testprop2 = Property(str, '') + + + +server = MMServerDataSource() +file = FileDataSource(file="serverdata.caf", name="data") +rsssource =file.new('RSSDataSource',url='https://aphro.site5.com/~doodoorg/tech/feed.php',name='name') +rsssource.delay = 60 +rsssource.active = True +print file.getChildren() +server.addChild(file) +if not len(file.getChildren()): + m = file.new('TestClass', name='node1', testprop='foo', testprop2='bla') + file.addChild(m) + m = file.new('TestClass', name='node2', testprop='bar', testprop2='stuff') + file.addChild(m) + +restserver = MMRestServer() +restserver.addChild(file) +restserver.addChild(rsssource) + +class CommandsServer(MMServerDataSource): + def addChild(self, child): + print " --> saving" + print file.getChildren() + print map(lambda s: s._datasource, file.getChildren()) + file.save() + +commands = CommandsServer() +server.port = 10110 +commands.port = 10113 +server.active = True +commands.active = True + +restserver.port = 8000 +restserver.active = True + +reactor.run() +print "saving..." +file.save() + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/examples/testserver.py /tmp/dmMTQQlFD1/metamodel-0.1.2/examples/testserver.py --- metamodel-0.1.1/examples/testserver.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/examples/testserver.py 2009-12-09 13:50:29.000000000 +0000 @@ -0,0 +1,27 @@ +from twisted.internet import reactor +from metamodel.datasources.twistedmm.server import MMServerDataSource +from metamodel.datasources.filesource import FileDataSource +#from metamodel.datasources.twistedmm.client import MMClientDataSource + + +server = MMServerDataSource() +file = FileDataSource(file="serverdata.caf", name="data") +server.addChild(file) +print file.getChildren() + +class CommandsServer(MMServerDataSource): + def addChild(self, child): + print " --> saving" + print file.getChildren() + print map(lambda s: s._datasource, file.getChildren()) + file.save() + +commands = CommandsServer() +server.port = 10110 +commands.port = 10113 +server.active = True +commands.active = True +reactor.run() +print "saving..." +file.save() + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/.hgignore /tmp/dmMTQQlFD1/metamodel-0.1.2/.hgignore --- metamodel-0.1.1/.hgignore 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/.hgignore 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,7 @@ +pyc$ +py~$ +swn$ +swo$ +swp$ +egg + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/.hgtags /tmp/dmMTQQlFD1/metamodel-0.1.2/.hgtags --- metamodel-0.1.1/.hgtags 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/.hgtags 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1 @@ +6562847b487d9ed6a0b4671e1ba89e20b9b55a51 0.1.2 diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/animation.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/animation.py --- metamodel-0.1.1/metamodel/animation.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/animation.py 2009-12-09 13:50:28.000000000 +0000 @@ -2,27 +2,27 @@ Animation system for models. """ -from .basemodel import SubscribableModel -from .properties import Property, SingleChoice, Vector2 +from basemodel import SubscribableModel +from properties import Property, SingleChoice, Vector2, PropertyFrom from math import sin, pi from cubicspline import cubicspline -from numpy import reshape,array +from numpy import array -def LINEAR(val): +def linear(val): """ Linear interpolation """ return val -def SINUS(val): +def sinus(val): """ Sinusoidal interpolation (goes from 0 to 1 following the curve of a sinus) """ val = (val-0.5)*pi return (sin(val)+1.0)/2.0 -inps = { "linear": LINEAR, - "sinus": SINUS } +INTERPOLATIONS = { "linear": linear, + "sinus": sinus } class ClockModel(SubscribableModel): time = Property(float, 0.0) @@ -71,9 +71,9 @@ childtimes = [] for child in children: childtimes.append(child.time) - splinedata.append([child.time+child.ctrl1[0],child.value+child.ctrl1[1]]) - splinedata.append([child.time,child.value]) - splinedata.append([child.time+child.ctrl2[0],child.value+child.ctrl2[1]]) + splinedata.append([child.time+child.ctrl1[0], child.value+child.ctrl1[1]]) + splinedata.append([child.time, child.value]) + splinedata.append([child.time+child.ctrl2[0], child.value+child.ctrl2[1]]) for idx, t in enumerate(childtimes[:-1]): next_t = childtimes[idx+1] if t <= currtime and currtime <= next_t: @@ -103,7 +103,7 @@ def check_channel(self, chan, currtime): children = chan.getChildren() - intp_function = inps[chan.interpolation] + intp_function = INTERPOLATIONS[chan.interpolation] if chan.loop: duration = children[-1].time if currtime > duration: @@ -150,6 +150,7 @@ if chan.interpolation in ["linear","sinus"]: self.check_channel(chan, val) elif chan.interpolation == "spline": + print "spline interpolation" self.check_spline_channel(chan, val) class AnimationKey(SubscribableModel): @@ -174,7 +175,7 @@ class AnimationChannel(SubscribableModel): name = Property(str,"animation channel") model = Property(SubscribableModel) - prop = Property(str,"") + prop = PropertyFrom("model") idx = Property(int,-1) loop = Property(bool, False) interpolation = SingleChoice(options=["linear","sinus","spline"], default="linear") @@ -187,12 +188,12 @@ klass = StringAnimationKey elif proptype == int: klass = IntAnimationKey - elif proptype in [float,list]: + elif proptype in [float, list]: klass = FloatAnimationKey elif issubclass(proptype, SubscribableModel): klass = ModelAnimationKey else: - raise ValueError,"property type not supported "+str(proptype) + raise ValueError, "property type not supported "+str(proptype) for time, value in points: self.addChild(self.new(klass, time=time, value=value)) @@ -204,12 +205,12 @@ clock = ClockModel() a = TestModel() manager = AnimationManager(clock=clock) - chan = AnimationChannel(model=a, prop="prop1", loop=True) - chan.addChild(IntAnimationKey(time=0, value=0)) - chan.addChild(IntAnimationKey(time=10, value=10.0)) + chan1 = AnimationChannel(model=a, prop="prop1", loop=True) + chan1.addChild(IntAnimationKey(time=0, value=0)) + chan1.addChild(IntAnimationKey(time=10, value=10.0)) lastkey = IntAnimationKey(time=20, value=5.0) - chan.addChild(lastkey) - manager.addChild(chan) + chan1.addChild(lastkey) + manager.addChild(chan1) # t = 0.0 clock.time = 0.0 assert(a.prop1 == 0.0) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/basemodel.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/basemodel.py --- metamodel-0.1.1/metamodel/basemodel.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/basemodel.py 2009-12-09 13:50:29.000000000 +0000 @@ -4,8 +4,8 @@ import traceback import uuid from collections import defaultdict -from meta import SubscribableModelMeta,ClassRegistry -from .instancereg import InstanceRegistry +from meta import SubscribableModelMeta, ClassRegistry +from instancereg import InstanceRegistry ######################################################## # reference model @@ -20,7 +20,7 @@ __metaclass__ = SubscribableModelMeta _instances = [] - def __init__(self,instance_uuid=None,datasource=None,**kwargs): + def __init__(self, instance_uuid=None, datasource=None, **kwargs): self._datasource = datasource self._evhs = [] self._children = [] @@ -33,30 +33,33 @@ # set property values myclass = self.__class__ kwargs = dict(kwargs) - for propname in myclass.properties: - if propname in kwargs: - setattr(self,propname,kwargs[propname]) - kwargs.pop(propname) + for propname, value in kwargs.iteritems(): + if propname in self.properties: + setattr(self, propname, value) else: - setattr(self,propname,getattr(myclass,propname)._default) - #self.setProperty(propname,getattr(myclass,propname)._default) - pass + self._props[propname] = value # set uuid if instance_uuid: self.uuid = instance_uuid else: self.uuid = uuid.uuid1() + def __str__(self): + return "Model:"+str(self.name)+" ("+self.__class__.__name__+")" + def trait(self, name): + """ + Return the trait class for a given property. + """ return getattr(self.__class__, name) - def get_uuid(self): + def _get_uuid(self): """ Getter function for the uuid property. """ return self._uuid - def set_uuid(self, value): + def _set_uuid(self, value): """ Setter function for the uuid property. @@ -64,7 +67,7 @@ soon as this is called. """ if not value.__class__ == uuid.UUID: - raise ValueError,"uuid is not an uuid.UUID!!" + raise ValueError,"uuid %s is not an uuid.UUID!!"%value.__class__.__name__ self._uuid = value self.on_uuid_set() InstanceRegistry.post(self) @@ -76,7 +79,7 @@ """ pass - uuid = property(get_uuid,set_uuid) + uuid = property(_get_uuid, _set_uuid) def new(self, clsname, instance_uuid=None, *args, **kwargs): """ @@ -89,7 +92,7 @@ *args, **kwargs) else: - if isinstance(clsname,str): + if isinstance(clsname, str): klass = ClassRegistry[clsname] else: klass = clsname @@ -133,7 +136,7 @@ if signal in self._callbacks and callback in self._callbacks[signal]: self._callbacks[signal].remove(callback) - def post_evh(self, name, *args): + def _post_evh(self, name, *args): """ Post a message. Only for internal use. """ @@ -142,10 +145,10 @@ try: getattr(evh, name)(*args) except: - print "Error on",evh,name + print self traceback.print_exc() - def post_signal(self, name, *args): + def _post_signal(self, name, *args): """ Send a signal. Only for internal use. """ @@ -156,16 +159,16 @@ """ Send a signal and post to general event handlers. """ - self.post_evh(name, *args) - self.post_signal(name, *args) + self._post_evh(name, *args) + self._post_signal(name, *args) def setProperty(self, name, value): """ Set a property to some value. Only for internal use. """ self._props[name] = value - self.post_evh("propertychange",name,value) - self.post_signal(name, value) + self._post_evh("propertychange", name, value) + self._post_signal(name, value) def getProperty(self, name): """ @@ -183,7 +186,8 @@ """ Delete a property from this instance. """ - del self._props[name] + if name in self._props: + del self._props[name] self.post("delproperty", name) def addChild(self, child): @@ -192,16 +196,16 @@ """ self._children.append(child) child._parents.append(self) - self.post("addchild",child) + self.post("addchild", child) def delChild(self, child): """ Delete a child. """ - self.post("delchild",child) + self.post("delchild", child) child._parents.remove(self) self._children.remove(child) - self.post("childdeleted",child) + self.post("childdeleted", child) def getParents(self): """ @@ -216,6 +220,9 @@ return self._children def getChildrenToPersist(self): + """ + Method for datasources to return children that should be persisted. + """ return self.getChildren() def getSelfToPersist(self): @@ -225,28 +232,109 @@ """ return self - def findChildren(self, name=None, ctype=None, recursive=False): - children = self._children + def getFromUrl(self, url): + """ + Get a model from a relative path in the following form: + /child1name/child2name/ -> child2 + """ + return self._getFromSplitUrl(url.split('/')) + + def _getFromSplitUrl(self, url): + """ + Get a model from url tokens. + """ + url = filter(lambda s: s, url) + next = self + for child in self.getChildren(): + next = child + for url_tok in url: + if url_tok: + next_test = next.findChild(url_tok) + if not next_test: + #print url_tok,map(lambda s: s.name, next.getChildren()) + raise ValueError, "cannot resolve url:"+str(url) + next = next_test + if next: + return next + + def findChildren(self, name=None, ctype=None, uuid=None, recursive=False, stack=None): + """ + Find children with a certain name or type. + """ + children = self.getAllReferences() if not name == None: children = filter(lambda s: s.name == name, children) if not ctype == None: children = filter(lambda s: isinstance(s, ctype), children) + if not uuid == None: + # XXX actually it doesnt make sense to look for uuid in get + # children, since there can be at most one, but saves some + # code atm :P + children = filter(lambda s: s.uuid == uuid, children) + if children: + return children + if recursive: + if stack == None: + stack = set([self]) + for child in self.getAllReferences(): + if child in stack: + continue + stack.add(child) + children += child.findChildren(name, ctype, uuid, recursive, stack) return children - def findChild(self, name=None, ctype=None, recursive=False): - children = self.findChildren(name, ctype, recursive) + def findChild(self, name=None, ctype=None, uuid=None, recursive=False): + """ + Find the first child with a certain name or type. + """ + children = self.findChildren(name, ctype, uuid, recursive) if children: - return children[0] + return children[0] + else: + return None + + def findParents(self, name=None, ctype=None, recursive=False, stack=None, **kwargs): + """ + Find parents with a certain name or type. + """ + parents = self._parents + if not name == None: + parents = filter(lambda s: s.name == name, parents) + if not ctype == None: + parents = filter(lambda s: isinstance(s, ctype), parents) + + for key, value in kwargs.iteritems(): + parents = filter(lambda s: getattr(s, key) == value, parents) + + if recursive: + if stack == None: + stack = set([self]) + for parent in self._parents: + if parent in stack: + continue + stack.add(parent) + parents += parent.findParents(name, ctype, recursive, stack, **kwargs) + + print "stack =", stack, "parents=", parents + + return parents + + def findParent(self, name=None, ctype=None, recursive=False, **kwargs): + """ + Find the first parent with a certain name or type. + """ + parents = self.findParents(name, ctype, recursive, **kwargs) + if parents: + return parents[0] else: - return None - + return None def purgeChildren(self): """ Unlink all children. """ children = list(self.getChildren()) - children.reverse() # shouldnt be needed later on, just to be nice to clients. + children.reverse() for child in children: self.delChild(child) @@ -270,8 +358,11 @@ allref += refsection return allref - def setReference(self, name, val): - self._references[self.name] = [] + #def _setReference(self, name, val): + # if val: + # self._references[name] = [val] + # else: + # self._references[name] = [] def invalidate(self, force=False): """ @@ -285,20 +376,19 @@ child.invalidate() else: # hiddenly remove the parenting info from the child. - # maybe should use delChild to get notification? ... dont think its necessary. child._parents.remove(self) for parent in list(self._parents): parent.delChild(self) # unref references for refcls in self._references: - setattr(self,refcls,None) + setattr(self, refcls, None) for refcls in self._referencedby.keys(): for ref in list(self._referencedby[refcls]): # remove self from people referencing us. - setattr(ref,refcls,None) + setattr(ref, refcls, None) try: self.__class__._instances.remove(self) - except: + except ValueError: pass # XXX already removed. probably needs more thought. else: self.post("invalidate") @@ -313,6 +403,9 @@ return newobj def deepclone(self, stack=None): + """ + Deep clone this object branch. + """ if stack == None: stack = {} if self in stack: @@ -324,10 +417,29 @@ newobj.addChild(child.deepclone(stack)) return newobj - def _getName(self): + def updateWith(self, aSubscribableModel, doReferences=True): + """ + Update all properties of this model using the values of the + given model. + """ + for propname in aSubscribableModel.properties: + # Ignore the uuid field since it should not be changed + if propname == "uuid": + continue + + if (not doReferences) and aSubscribableModel.trait(propname)._reference: + continue + + old = getattr(self, propname) + new = getattr(aSubscribableModel, propname) + if old != new: + setattr(self, propname, new) + + def _get_name(self): + """name getter""" return self.__class__.__name__ - name = property(_getName) + name = property(_get_name) builds = [] builtby = [] @@ -337,9 +449,13 @@ Class for models of a yet unknown model class. """ # dont publish uuid - def get_uuid(self): + def _get_uuid(self): + """uuid getter""" return self._uuid - def set_uuid(self,val): + + def _set_uuid(self, val): + """uuid setter""" self._uuid = val - uuid = property(get_uuid,set_uuid) + + uuid = property(_get_uuid, _set_uuid) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/baseview.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/baseview.py --- metamodel-0.1.1/metamodel/baseview.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/baseview.py 2009-12-09 13:50:29.000000000 +0000 @@ -16,38 +16,64 @@ def __init__(self, view, parent, model): model.subscribe(self) self._view = view - self._parents = [parent] + if parent: + self._parents = [parent] + else: + self._parents = [] self._model = model self._instance = None def getParentViews(self): - return map(lambda s: self._view._instances[s.uuid], self._parents) + """ + Get view nodes connected to the parent models. + """ + views = [] + instances = self._view._instances + for parent in self._parents: + if parent: + if parent.uuid in instances: + views.append(instances[parent.uuid]) + return views def getChildrenViews(self): + """ + Get view nodes connected to the children models. + """ children = self._model.getChildren() - instanced = filter(lambda s: s.uuid in self._view._instances, children) - children = map(lambda s: self._view._instances[s.uuid], instanced) + instances = self._view._instances + instanced = filter(lambda s: s.uuid in instances, children) + children = map(lambda s: instances[s.uuid], instanced) return children # view "callbacks" def addparent(self, parent): + """ + Add a parent node to this object. + """ self._parents.append(parent) def unlink(self): + """ + Object unlinked from some parents. + """ pass # model callbacks def addchild(self, child): + """addchild callback""" self._view.traverse(self._model, child) def delchild(self, child): + """delchild callback""" self._view.removeBranch(self._model, child) def propertychange(self, name, value): + """propertychange callback""" if hasattr(self.__class__, name): setattr(self, name, value) def invalidate(self): + """invalidate callback""" self._model.unsubscribe(self) @@ -62,6 +88,7 @@ Subclasses are responsible for declaring their class mappings, and holding common data for the engine (all children get a pointer to the view). """ + _model2view = {} def __init__(self, model): self._model = model self._instances = {} @@ -69,24 +96,44 @@ model.subscribe(self) def getViewNode(self, model): + """ + Get the view node instantiated for the given model. + """ return self._instances.get(model.uuid, None) - def removeBranch(self, parent, model): + def removeBranch(self, _, model): + """ + Remove a branch from the view in reaction to a model branch + removal (normally you remove the model instead). + """ if model.uuid in self._instances: for child in model.getChildren(): self.removeBranch(model, child) self._instances[model.uuid].unlink() del self._instances[model.uuid] - def traverse(self, parent, model): + def traverse(self, parent, model, ctypes=None): + """ + Traverse, mirror and subscribe to a model. + """ if model.uuid in self._instances and parent.uuid in self._instances: self._instances[model.uuid].addparent(parent) else: - self.process(parent, model) + self.process(parent, model, ctypes) for child in model.getChildren(): - self.traverse(model, child) + self.traverse(model, child, ctypes) - def process(self, parent, model): + def _is_child_of(self, model, ctypes): + for ctype in ctypes: + if isinstance(model, ctype): + return True + + def process(self, parent, model, ctypes): + """ + Generate a view node for a model. + """ + if ctypes and not self._is_child_of(model, ctypes): + return class_name = model.__class__.__name__ if not class_name in self._model2view: parents = map(lambda s: s.__name__, model.__class__.__mro__) @@ -103,8 +150,14 @@ # model callbacks def addchild(self, child): + """ + mm addchild callback. + """ self.traverse(self._model, child) def delchild(self, child): + """ + mm delchild callback. + """ self.removeBranch(self._model, child) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/activable.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/activable.py --- metamodel-0.1.1/metamodel/datasources/activable.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/metamodel/datasources/activable.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,22 @@ +from metamodel.datasources import DataSource + +class ActivableDataSource(DataSource): + def __init__(self, *args, **kwargs): + self._connected = False + active = None + if "active" in kwargs: + active = kwargs.pop("active") + DataSource.__init__(self, *args, **kwargs) + if not active == None: + self.active = active + + # Activate + def setProperty(self, name, value): + DataSource.setProperty(self, name, value) + if name == "active": + if value == False and self._connected: + self.disconnect() + elif value == True and not self._connected: + self.connect() + + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/dokuwiki.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/dokuwiki.py --- metamodel-0.1.1/metamodel/datasources/dokuwiki.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/metamodel/datasources/dokuwiki.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,114 @@ +from twisted.internet import threads, reactor + +from xmlrpclib import ServerProxy +from urllib import urlencode + +from metamodel import DataSource, SubscribableModel +from metamodel import Link, Property, Password + +from time import strptime, mktime + +class DokuwikiPage(SubscribableModel): + name = Property(str, "", ro=True) + id = Property(str, "", ro=True) + timestamp = Property(float, 0, ro=True) + perms = Property(int, 8, ro=True) + size = Property(int, 0, ro=True) + +class DokuwikiSection(SubscribableModel): + name = Property(str, "") + id = Property(str, "") + +class Dokuwiki(DataSource): + name = Property(str, "Dokuwiki Source") + url = Link("") + user = Property(str, "") + password = Password("") + active = Property(bool, False) + + def __init__(self, *args, **kwargs): + self._connected = False + active = None + if "active" in kwargs: + active = kwargs.pop("active") + DataSource.__init__(self, *args, **kwargs) + if not active == None: + self.active = active + + # Activate + def setProperty(self, name, value): + SubscribableModel.setProperty(self, name, value) + if name in ["active"]: + if value == False and self._connected: + self.disable() + elif value == True and not self._connected: + self.enable() + + def enable(self): + self.connect() + + def disable(self): + pass + + # put a page into the page tree + def add_page(self, page): + name = page["id"] + path = name.split(":") + print " *", page + parent = self + for i, pathm in enumerate(path): + if i == len(path)-1: # a page + t = mktime(strptime(page['lastModified'].value,"%Y-%m-%dT%H:%M:%S")) + + new = self.new(DokuwikiPage, + id = name, + name = pathm, + timestamp = t, + perms = int(page['perms']), + size = page['size']) + parent.addChild(new) + self._sections[name] = new + else: # a namespace + part_path = ":".join(path[:i+1]) + if not part_path in self._sections: + new = self.new(DokuwikiSection, + id = name, + name = pathm) + self._sections[part_path] = new + parent.addChild(new) + else: + new = self._sections[part_path] + + parent = new + + def getChildrenToPersist(self): + return [] + + def callDeferred(self, get_func, got_func): + d = threads.deferToThread(get_func) + d.addCallback(got_func) + + def _getPageList(self): + return self._rpc.wiki.getAllPages() + + def _gotPageList(self, pages): + self._sections = {} + self.purgeChildren() + for page in pages: + self.add_page(page) + self._connected = True + + def get_pagelist(self): + self.callDeferred(self._getPageList, self._gotPageList) + + def connect(self): + # following commented line is for gtkhtml (not used) + #simplebrowser.currentUrl = self.view.url.get_text() + # handle response + params = urlencode({'u':self.user,'p':self.password}) + fullurl = self.url + "/lib/exe/xmlrpc.php?"+ params + self._rpc = ServerProxy(fullurl) + print "connect!" + #self.get_version() + self.get_pagelist() + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/filesource.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/filesource.py --- metamodel-0.1.1/metamodel/datasources/filesource.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/filesource.py 2009-12-09 13:50:28.000000000 +0000 @@ -9,6 +9,7 @@ from metamodel.yamlserializer import LoadModel, SaveModel from metamodel.datasources import DataSource, DataSourceRoot +from metamodel.instancereg import InstanceRegistry class FileDataSource(DataSource): file = File(["caf","xcaf"]) @@ -29,6 +30,7 @@ f.close() self.purgeChildren() dsroot = LoadModel(data, "DataSourceRoot", self)[0] + InstanceRegistry.replace_listener(dsroot, self) objects = dsroot.getChildren() for obj in objects: # use parent addChild so we don't get double add into datasource @@ -46,3 +48,4 @@ f.close() builtby = ["DataSource"] + builts = ["SubscribableModel"] diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/hglogs.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/hglogs.py --- metamodel-0.1.1/metamodel/datasources/hglogs.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/metamodel/datasources/hglogs.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,97 @@ +import time +from ..datasources import DataSource +from metamodel.basemodel import SubscribableModel +from metamodel.properties import Link,Property +from twisted.internet import threads,reactor + +class HgChangeSet(SubscribableModel): + name = Property(str, "SVN Changeset") + author = Property(str, "") + timestamp = Property(float, 0.0) + revision = Property(int, 0.0) + + +class HgLogs(DataSource): + name = Property(str, "SVN Source") + url = Link("") + active = Property(bool, False) + delay = Property(int, 10) + def __init__(self, *args, **kwargs): + self._connected = False + active = None + if "active" in kwargs: + active = kwargs.pop("active") + DataSource.__init__(self, *args, **kwargs) + if not active == None: + self.active = active + + def getChildrenToPersist(self): + return [] + + # Activate + def setProperty(self, name, value): + SubscribableModel.setProperty(self, name, value) + if name in ["active"]: + if value == False and self._connected: + self.stopDownload() + elif value == True and not self._connected: + reactor.callLater(5,self.startDownload) + elif name == "delay" and self.active: + self.stopDownload() + self.startDownload() + + def getHgLogs(self): + from mercurial import hg,ui,commands + class MyUi(ui.ui): + def __init__(self): + ui.ui.__init__(self) + self._newitem = None + def parseHgLine(self, data): + name,val = data.strip().split(":",1) + return val.strip() + def write(s, data): + if data.startswith("changeset"): + val = s.parseHgLine(data) + s._newitem = self.new(HgChangeSet,changeset=val) + self.addChild(s._newitem) + elif data.startswith("branch"): + val = s.parseHgLine(data) + elif data.startswith("user"): + val = s.parseHgLine(data) + s._newitem.author = val + elif data.startswith("date"): + val = s.parseHgLine(data) + val = val.split("+")[0].strip() + s._newitem.timestamp = time.mktime(time.strptime(val)) + elif data.startswith("summary"): + val = s.parseHgLine(data) + s._newitem.name = val + elif data == '\n' and s._newitem: + s._newitem = None + uio = MyUi() + r = hg.repository(uio, path=self.url) + commands.log(uio, r, rev=0, copies=False, date=0, only_branch=0, + no_merges=0, only_merges=0, keyword=0, user=0) + + def gotHgLogs(self, logs): + for alog in logs: + author = "unknown" + if "author" in alog: + author = alog.author + self.addChild(self.new(SvnChangeSet, + name=alog.message, + timestamp=alog.date, + author=author, + revision=alog.revision.number + )) + def someError(self, *args): + self.active = False + + def startDownload(self): + self.getHgLogs() + #d = threads.deferToThread(self.getSvnLogs) + #d.addCallback(self.gotSvnLogs) + #d.addErrback(self.someError) + + def stopDownload(self): + pass diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/__init__.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/__init__.py --- metamodel-0.1.1/metamodel/datasources/__init__.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/__init__.py 2009-12-09 13:50:28.000000000 +0000 @@ -23,7 +23,7 @@ from metamodel.basemodel import SubscribableModel from metamodel.properties import Property -from ..meta import ClassRegistry +from metamodel.meta import ClassRegistry class Folder(SubscribableModel): name = Property(str,"a folder") @@ -59,6 +59,36 @@ else: SubscribableModel.invalidate(self) + def own(self, model, recursive=True, stack=None): + """ + Own a model, by releasing from the previous datasource + and aquiring it. + """ + if not stack: + stack = [] + if not model in stack: + if model._datasource: + model._datasource.release(model) + self.accept(model) + if recursive: + stack.append(model) + for child in model.getAllReferences(): + self.own(child, recursive, stack) + + def accept(self, model): + """ + Accept a model into this datasource. + Throw an exception if the datasource cannot accept. + """ + model._datasource = self + + def release(self, model): + """ + Release a model from this datasource. + Throw an exception if the datasource cannot release. + """ + model._datasource = None + class DataSourceRoot(SubscribableModel): """ diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/restserver.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/restserver.py --- metamodel-0.1.1/metamodel/datasources/restserver.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/metamodel/datasources/restserver.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,210 @@ +from twisted.internet.protocol import Protocol + +import os +import uuid +from twisted.internet.protocol import Factory +from twisted.internet import reactor + +from twisted.internet.interfaces import IReactorSSL +try: + from twisted.internet.ssl import DefaultOpenSSLContextFactory +except: + pass # XXX no ssl support! + +import metamodel +from metamodel import Property, File +from metamodel.datasources import DataSource +from metamodel.yamlserializer import SaveModel +from metamodel.meta import ClassRegistry +from metamodel.dictserializer import find_uuid + +import simplejson + +class MetamodelRestProtocol(Protocol): + # connection state + transport = None + factory = None + + def dataReceived(self, data): + split_data = data.split("\n") + idx = split_data.index('\r') + data = "\n".join(split_data[idx+1:]) + first_line_split = split_data[0].split(" ") + command = first_line_split[0].upper() + url = first_line_split[1].strip() + if command == "GET": + self.getReceived(url, data) + elif command == "PUT": + self.putReceived(url, data) + elif command == "POST": + self.postReceived(url, data) + elif command == "DELETE": + self.deleteReceived(url, data) + self.transport.loseConnection() + + def putReceived(self, url, data): + model = self.getModelFromUrl(url) + data = simplejson.loads(data) + for key, val in data.iteritems(): + if isinstance(val, str): + val = str(val) + setattr(model, str(key), val) + print " * put received",data + def postReceived(self, url, data): + model = self.getModelFromUrl(url) + data = simplejson.loads(data) + print data + new_model = model.new(str(data['mm'])) + print new_model + for key, val in data.iteritems(): + if key == 'mm': + continue + if new_model.trait(key)._reference: + val = find_uuid(uuid.UUID(val)) + elif isinstance(val, str): + val = str(val) + setattr(new_model, str(key), val) + model.addChild(new_model) + print " * post received" + def deleteReceived(self, url, data): + print " * delete received",url + model = self.getModelFromUrl(url) + model.invalidate() + def getReceived(self, url, data): + if url == "/schema/": + class_name = "MetaModel" + acls = ClassRegistry[class_name] + data = self.serializeNodeList(acls.get_instances()) + elif url.startswith("/classes/"): + class_name = url.split("/")[2] + acls = ClassRegistry[class_name] + if url.endswith("/"): + data = self.serializeNodeChildren(acls._model) + else: + data = self.serializeNodeProperties(acls._model) + elif url.startswith("/instances/"): + class_name = url.split("/")[2] + acls = ClassRegistry[class_name] + data = self.serializeNodeList(acls.get_instances()) + else: + print url + model = self.getModelFromUrl(url) + print model + if url.endswith('/'): + data = self.serializeNodeChildren(model) + else: + data = self.serializeNodeProperties(model) + self.transport.write("HTTP/1.0 200 Found\n") + self.transport.write("Content-Type: text/json; charset=UTF-8\n\n") + + self.transport.write(data) + def getModelFromUrl(self, url): + schema = False + if url.startswith('/schema/'): + schema = True + url = url[8:] + model = self.factory.getFromUrl(url) + if schema: + model = model._model + return model + def serializeNodeProperties(self, model): + data_dict = {} + data_dict['uuid'] = str(model.uuid) + for prop in model.properties: + if model.trait(prop)._reference: + child = getattr(model, prop) + if child: + data_dict[prop] = str(child.uuid) + else: + data_dict[prop] = getattr(model, prop) + data_dict['name'] = model.name + data_dict['mm'] = model.__class__.__name__ + json_str = simplejson.dumps(data_dict) + return json_str + + def serializeNodeChildren(self, model): + return self.serializeNodeList(model.getChildren()) + + def serializeNodeList(self, nodelist): + data_list = [] + for node in nodelist: + data_dict = {} + data_dict['uuid'] = str(node.uuid) + for prop in node.properties: + print node + val = getattr(node, prop) + if node.trait(prop)._reference: + if val: + val = str(val.uuid) + if not val == None: + data_dict[prop] = val + + data_dict['name'] = node.name + data_dict['mm'] = node.__class__.__name__ + data_list.append(data_dict) + try: + json_str = simplejson.dumps(data_list) + except: + print "PRobLEMS SERIALIZING"+str(data_list) + return json_str + + def connectionMade(self): + """ send current world state """ + # we have a client! + self.factory._clients.append(self) + + def connectionLost(self, reason): + """ connection to client lost """ + self.factory._clients.remove(self) + + + +class MetamodelRestServerFactory(Factory): + protocol = MetamodelRestProtocol + + + +class MMRestServer(DataSource, MetamodelRestServerFactory): + port = Property(int, 8000) + active = Property(bool, False) + connected = False + key = File(["key"],"test/server.key") + certificate = File(["crt"],"test/server.crt") + + def __init__(self, *args, **kwargs): + self.state = 0 + active = None + if "active" in kwargs: + active = kwargs.pop("active") + DataSource.__init__(self, *args, **kwargs) + self._clients = [] + self._proto = self # hack so we can use the same instance guardian as the client + if not active == None: + self.active = active + + # hook 'active' to activate the connection. note at the moment + # all other properties must be already setup by the time the source + # is activated. + def setProperty(self, name, value): + DataSource.setProperty(self, name, value) + if name == "active" and value == True and not self.connected: + try: + if self.port == 8001 and os.path.exists(self.key) and os.path.exists(self.certificate): + self._ctx = DefaultOpenSSLContextFactory(self.key, self.certificate) + reactorssl = IReactorSSL(reactor) + reactorssl.listenSSL(self.port, self, self._ctx) + else: + reactor.listenTCP(self.port, self) + print "listenTCP",self.port + self.connected = True + except: + self.connected = False + + + buids = ["NetworkedModel"] + builtby = ["DataSource"] + + + + + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/rsssource.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/rsssource.py --- metamodel-0.1.1/metamodel/datasources/rsssource.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/rsssource.py 2009-12-09 13:50:28.000000000 +0000 @@ -6,25 +6,30 @@ from metamodel.basemodel import SubscribableModel from metamodel.properties import Property, Link -from metamodel.yamlserializer import LoadModel, SaveModel -from metamodel.datasources import DataSource, DataSourceRoot +from metamodel.datasources import DataSource from twisted_feeder import FeederFactory, FeederProtocol from twisted.internet import task class RSSItem(SubscribableModel): - name = Property(str,"an rss item") - updated = Property(str,"last updated") - timestamp = Property(float,0.0) + """ + An rss item. + """ + name = Property(str, "an rss item") + updated = Property(str, "last updated") + timestamp = Property(float, 0.0) class RSSDataSource(DataSource, FeederProtocol): + """ + An rss data feed. + """ name = Property(str, "RSS Source") url = Link("") active = Property(bool, False) delay = Property(int, 10) - title = Property(str,"",ro=True) + title = Property(str, "", ro=True) def __init__(self, *args, **kwargs): - self._l = None + self._looping_call = None FeederProtocol.__init__(self) self._connected = False self.factory = FeederFactory('.') @@ -33,12 +38,12 @@ self._lastidx = 0 active = None if "active" in kwargs: - active = kwargs.pop("active") + active = kwargs.pop("active") DataSource.__init__(self, *args, **kwargs) if not active == None: self.active = active - def workOnPage(self, parsed_feed, addr): + def workOnPage(self, parsed_feed, _): """ callback with the parsed feed. """ @@ -49,16 +54,20 @@ if not prevtitle == self.title: if not self.isDefault('name'): self.name = self.title - for e in parsed_feed["entries"]: - f_time = time.mktime(e["updated_parsed"]) + for entry in parsed_feed["entries"]: + if "updated_parsed" in entry: + f_time = time.mktime(entry["updated_parsed"]) + else: + f_time = time.time() if not f_time in self._entry_dict: - self._entry_dict[f_time] = e + self._entry_dict[f_time] = entry #entry_dict[f_time] = titles[i]+" "+e["title"] self._entry_times.append(f_time) self._entry_times.sort() while self._lastidx < len(self._entry_dict): - self.textReceived(self._entry_dict[self._entry_times[self._lastidx]]) + entry = self._entry_dict[self._entry_times[self._lastidx]] + self.textReceived(entry) self._lastidx += 1 return parsed_feed @@ -70,24 +79,27 @@ item = self.new(RSSItem, name=title) item._datasource = self for prop in data.keys(): - if isinstance(data[prop],unicode): - if not hasattr(RSSItem,prop): - if prop == "link": - p = Link("",ro=True) - else: - p = Property(str,"",ro=True) - p.name = prop - RSSItem.properties.append(prop) - setattr(RSSItem,prop,p) - setattr(item,prop,data[prop].encode('latin-1','ignore').strip()) + if isinstance(data[prop], unicode): + if not hasattr(RSSItem, prop): + if prop == "link": + prop_obj = Link("", ro=True) + else: + prop_obj = Property(str, "", ro=True) + prop_obj.name = prop + RSSItem.properties.append(prop_obj) + setattr(RSSItem, prop, prop_obj) + setattr(item, + prop, + data[prop].encode('latin-1', 'ignore').strip()) if "updated" in data: try: - #t = time.mktime(time.strptime(data["updated"],"%a, %d %b %Y %H:%M:%S %Z")) - t = time.mktime(data["updated_parsed"]) - except: - print "CANT DECODE TIME!!!:",data["updated"] - t = 666.0 - setattr(item,"timestamp",float(t)) + #t = time.mktime(time.strptime(data["updated"], + # "%a, %d %b %Y %H:%M:%S %Z")) + atime = time.mktime(data["updated_parsed"]) + except KeyError: + print "CANT DECODE TIME!!!:", data["updated"] + atime = 666.0 + setattr(item, "timestamp", float(atime)) self.addChild(item) # Activate @@ -106,13 +118,20 @@ self.startDownload() def startDownload(self): - self._l = task.LoopingCall(self.start,[[self.url]], self.factory.cacheDir, False) - self._l.start(self.delay) + """ + Start downloading the feed. + """ + self._looping_call = task.LoopingCall(self.start, + [[self.url]], self.factory.cacheDir, False) + self._looping_call.start(self.delay) #self.start([[self.url]], self.factory.cacheDir, False) def stopDownload(self): - if self._l: - self._l.stop() - self._l = None + """ + Stop downloading. + """ + if self._looping_call: + self._looping_call.stop() + self._looping_call = None builtby = ["DataSource"] diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/svnlogs.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/svnlogs.py --- metamodel-0.1.1/metamodel/datasources/svnlogs.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/metamodel/datasources/svnlogs.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,68 @@ +from ..datasources import DataSource +from metamodel.basemodel import SubscribableModel +from metamodel.properties import Link,Property +from twisted.internet import threads,reactor + +class SvnChangeSet(SubscribableModel): + name = Property(str, "SVN Changeset") + author = Property(str, "") + timestamp = Property(float, 0.0) + revision = Property(int, 0.0) + + +class SvnLogs(DataSource): + name = Property(str, "SVN Source") + url = Link("") + active = Property(bool, False) + delay = Property(int, 10) + def __init__(self, *args, **kwargs): + self._connected = False + active = None + if "active" in kwargs: + active = kwargs.pop("active") + DataSource.__init__(self, *args, **kwargs) + if not active == None: + self.active = active + + def getChildrenToPersist(self): + return [] + + # Activate + def setProperty(self, name, value): + SubscribableModel.setProperty(self, name, value) + if name in ["active"]: + if value == False and self._connected: + self.stopDownload() + elif value == True and not self._connected: + reactor.callLater(5,self.startDownload) + elif name == "delay" and self.active: + self.stopDownload() + self.startDownload() + + def getSvnLogs(self): + from pysvn import Client + c = Client() + logs = c.log(self.url) + return logs + + def gotSvnLogs(self, logs): + for alog in logs: + author = "unknown" + if "author" in alog: + author = alog.author + self.addChild(self.new(SvnChangeSet, + name=alog.message, + timestamp=alog.date, + author=author, + revision=alog.revision.number + )) + def someError(self, *args): + self.active = False + + def startDownload(self): + d = threads.deferToThread(self.getSvnLogs) + d.addCallback(self.gotSvnLogs) + d.addErrback(self.someError) + + def stopDownload(self): + pass diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/twisted_feeder.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/twisted_feeder.py --- metamodel-0.1.1/metamodel/datasources/twisted_feeder.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/twisted_feeder.py 2009-12-09 13:50:28.000000000 +0000 @@ -8,9 +8,9 @@ from twisted.internet import reactor, protocol, defer from twisted.web import client from twisted.web.client import HTTPPageGetter, HTTPClientFactory -from twisted.python import failure -from twisted.web import error -import feedparser, time, sys +#from twisted.python import failure +#from twisted.web import error +import feedparser, time import md5, os try: @@ -72,11 +72,11 @@ f.write(modtime[0]) def getHashForUrl(self, url): - hash = md5.new() - hash.update(url) - return hash.hexdigest() + md5sum = md5.new() + md5sum.update(url) + return md5sum.hexdigest() - def notModified(): + def notModified(self): if self.waiting: self.waiting = 0 @@ -137,7 +137,7 @@ # of the feed at address key, the first element of the tuple is the # timestamp #print "Getting from memory..." - return defer.succeed(cache.get(key,key)[1]) + return defer.succeed(cache.get(key, key)[1]) def parseFeed(self, feed): # This is self explaining :) @@ -157,7 +157,7 @@ if cache.get(addr, None): cache[addr] = (time.time(), feed) else: - cache.setdefault(addr, (time.time(),feed)) + cache.setdefault(addr, (time.time(), feed)) return feed def workOnPage(self, parsed_feed, addr): @@ -165,7 +165,7 @@ # which you can eventually save the structure. print "-"*20 print "finished retrieving" - print "Feed Version:",parsed_feed.get('version','Unknown') + print "Feed Version:", parsed_feed.get('version', 'Unknown') #print parsed_feed["entries"] # @@ -194,23 +194,17 @@ return parsed_feed def stopWorking(self, data=None): - print "Closing connection number %d..."%(self.parsed,) + print "Closing connection number %d..." % (self.parsed,) print "=-"*20 # This is here only for testing. When a protocol/interface will be # created to communicate with this rss-aggregator server, we won't need # to die after we parsed some feeds just one time. + # XXX should probably do something... self.parsed += 1 - print self.parsed, self.END_VALUE - if self.parsed > self.END_VALUE: # - print "Closing all..." # - for i in self.error_list: # Just for testing sake - print i # - print len(self.error_list) # - reactor.stop() # def getPage(self, data, args): - return conditionalGetPage(self.cacheDir,args,timeout=TIMEOUT) + return conditionalGetPage(self.cacheDir, args, timeout=TIMEOUT) def printStatus(self, data=None): pass @@ -267,7 +261,7 @@ if len(addresses) > DEFERRED_GROUPS: url_groups = [[] for x in xrange(DEFERRED_GROUPS)] for i, addr in enumerate(addresses): - url_groups[i%DEFERRED_GROUPS].append(addr) + url_groups[i % DEFERRED_GROUPS].append(addr) else: url_groups = [[addr] for addr in addresses] @@ -287,7 +281,7 @@ return rss_feeds else: return None -if __name__=="__main__": - f = FeederFactory(cacheDir='.',std_alone=True) +if __name__ == "__main__": + f = FeederFactory(cacheDir='.', std_alone=True) reactor.run() diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/twistedmm/client.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/twistedmm/client.py --- metamodel-0.1.1/metamodel/datasources/twistedmm/client.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/twistedmm/client.py 2009-12-09 13:50:28.000000000 +0000 @@ -1,34 +1,37 @@ -from twisted.internet.protocol import Protocol, ReconnectingClientFactory +from twisted.internet.protocol import ReconnectingClientFactory from twisted.internet import reactor from twisted.internet.interfaces import IReactorSSL from twisted.internet.ssl import ClientContextFactory -from sys import stdout - -from metamodel.basemodel import SubscribableModel from metamodel.properties import Property -from metamodel.yamlserializer import LoadModel, SaveModel -from metamodel.datasources import DataSource, DataSourceRoot - -from .proto import MetamodelProtocol1 -from .guardian import InstanceGuardian -from .model import NetworkedModel +from metamodel.datasources import DataSource -import sys +from proto import MetamodelProtocol1 +from guardian import InstanceGuardian class MetamodelClientProtocol1(MetamodelProtocol1): + """ + twistedmm client protocol + """ # responses to arrived messages def clientOK(self): # make messages coming to server uuid go to ourselves instead. self.factory._instances[str(self.server_uuid)] = self.factory + self.factory.clientConnected() def setProperty(self, data, obj_uuid, name, val): self.state = 2 setattr(self.factory._instances[obj_uuid], name, val) self.state = 1 + def setReference(self, data, obj_uuid, name, val_uuid): + self.state = 2 + val = self.factory._instances[val_uuid] + setattr(self.factory._instances[obj_uuid], name, val) + self.state = 1 + def addChild(self, data, parent, child): self.state = 2 parent.addChild(child) @@ -46,9 +49,15 @@ class MetamodelClientFactory(ReconnectingClientFactory): + """ + twistedmm client factory + """ def startedConnecting(self, connector): print 'Started to connect.' + def clientConnected(self): + pass + def buildProtocol(self, addr): self.resetDelay() proto = MetamodelClientProtocol1() @@ -67,6 +76,9 @@ class MMClientDataSource(DataSource, MetamodelClientFactory): + """ + twistedmm client datasource + """ server = Property(str,'localhost') port = Property(int, 10110) active = Property(bool, False) @@ -78,10 +90,13 @@ self._invalidating = False active = None if "active" in kwargs: - active = kwargs.pop("active") + active = kwargs.pop("active") DataSource.__init__(self, *args, **kwargs) if not active == None: - self.active = active + self.active = active + + def clientConnected(self): + self.post('connected') def getChildrenToPersist(self): return [] @@ -99,11 +114,19 @@ def new(self,*args,**kwargs): inst = DataSource.new(self, *args, **kwargs) + self.accept(inst) + return inst + + def release(self, inst): + self._proto.server_node.delChild(inst) + DataSource.release(self, inst) + + def accept(self, inst): + DataSource.accept(self, inst) InstanceGuardian(inst, self) self._instances[str(inst.uuid)] = inst if self._proto and self._proto.state == 1: self._proto.sendNew(inst) - return inst def addChild(self, child): DataSource.addChild(self, child) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/twistedmm/guardian.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/twistedmm/guardian.py --- metamodel-0.1.1/metamodel/datasources/twistedmm/guardian.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/twistedmm/guardian.py 2009-12-09 13:50:28.000000000 +0000 @@ -1,35 +1,67 @@ -# This is the instance guardian which listens to objects to replicate -# changes on the network. It is more client oriented, but some code -# can be reused for the server +""" +Instance guardian. + +Listens to objects to replicate changes on the network. +It is more client oriented, but some code can be reused for the server +""" +from metamodel import SubscribableModel + class InstanceGuardian(object): + """ + A model guardian. + """ def __init__(self, model, datasource): self._model = model self._datasource = datasource self._model.subscribe(self) # events from the model + def get_proto(self): + """ + Get the client protocol object. + """ + return self._datasource._proto + def propertychange(self, name, value): - if not self._datasource._proto.state == 1: - return - self._datasource._proto.sendPropertyChange(self._model, name, value) + """ + Callback for property change. + """ + if not self.get_proto().state == 1: + return + if isinstance(value, SubscribableModel): + print "propchange",value,value._datasource,self._datasource + if value._datasource == self._datasource: + print "send refchange",value + self.get_proto().sendReferenceChange(self._model, name, value) + else: + self.get_proto().sendPropertyChange(self._model, name, value) def addchild(self, child): + """ + Callback for child addition. + """ if not child._datasource == self._datasource: - return # its not our node - if not self._datasource._proto.state == 1: + return # its not our node + if not self.get_proto().state == 1: return - self._datasource._proto.sendAddChild(self._model, child) + self.get_proto().sendAddChild(self._model, child) def delchild(self, child): + """ + Callback for child removal. + """ if not child._datasource == self._datasource: - return # its not our node - if not self._datasource._proto.state == 1: + return # its not our node + if not self.get_proto().state == 1: return - self._datasource._proto.sendDelChild(self._model, child) + self.get_proto().sendDelChild(self._model, child) def invalidate(self): - if not self._datasource._proto.state == 1: + """ + Callback for invalidate. + """ + if not self.get_proto().state == 1: return - self._datasource._proto.sendInvalidate(self._model) + self.get_proto().sendInvalidate(self._model) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/twistedmm/model.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/twistedmm/model.py --- metamodel-0.1.1/metamodel/datasources/twistedmm/model.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/twistedmm/model.py 2009-12-09 13:50:28.000000000 +0000 @@ -1,9 +1,12 @@ +""" +Some extra models for twistedmm. +""" + from metamodel.basemodel import SubscribableModel from metamodel.properties import Property class NetworkedModel(SubscribableModel): builds = ["SubscribableModel"] - class NetworkedDataSource(SubscribableModel): - pass + builds = ["SubscribableModel"] diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/twistedmm/proto.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/twistedmm/proto.py --- metamodel-0.1.1/metamodel/datasources/twistedmm/proto.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/twistedmm/proto.py 2009-12-09 13:50:28.000000000 +0000 @@ -2,7 +2,7 @@ from metamodel.yamlserializer import LoadModel, SaveModel, LoadValue, SaveValue import sys -from .model import NetworkedModel +from model import NetworkedModel from metamodel import dynamicmeta @@ -12,6 +12,10 @@ def PC(model, name, value): return "PC:"+str(model.uuid)+":"+name+":"+SaveValue(value)+"\n" +def REF(model, name, value): + if value: + return "REF:"+str(model.uuid)+":"+name+":"+str(value.uuid)+"\n" + def DEL(parent, child): return "DELCHILD:"+str(parent.uuid)+":"+str(child.uuid)+"\n" @@ -28,82 +32,99 @@ class MetamodelProtocol1(Protocol): lines= "" receiving = 0 + receiving_line = False state = 0 + transport = None + factory = None def dataReceived(self, data): + if self.receiving_line: + data = self.receiving_data + data + self.receiving_line = False lines = data.split("\n") for idx,line in enumerate(lines): if idx == len(lines)-1: - self.lineReceived(line, lastline=True) + if not line: + # XXX stupid + self.lineReceived(line, lastline=True) + else: + self.receiving_line = True + self.receiving_data = line else: self.lineReceived(line) - def sendOntologies(self): + def sendNamespaces(self): + print " * send ontologies" self.transport.write("ONTOLOGIES\n") data = SaveModel(dynamicmeta.Registry, userfunc=self.transport.write) self.transport.write("\nENDONTOLOGIES\n") - def loadOntologies(self, data): + def loadNamespaces(self, data): + self.factory.state = 1 ontologies = LoadModel(data, "InstanceRegistryModel")[0].getChildren() + self.factory.state = 2 for ont in ontologies: - print " * load Ontology:",ont.name + print " * load Namespace:",ont.name dynamicmeta.Registry.addChild(ont) def lineReceived(self, data, lastline=False): if self.receiving == 1: - if data.startswith("ENDNEW"): - instdata = self.lines - self.receiving = 0 - self.lines = "" - self.state = 2 - self.factory.state = 2 - instances = LoadModel(instdata,datasource=self.factory) - self.factory.state = 1 - self.state = 1 - self.newInstances(instdata, instances) - else: - if lastline: - self.lines += data - else: - self.lines += data+"\n" + if data.startswith("ENDNEW"): + instdata = self.lines + self.receiving = 0 + self.lines = "" + self.state = 2 + self.factory.state = 2 + instances = LoadModel(instdata, datasource=self.factory) + for inst in instances: + print " * new:",inst.name,inst.uuid + self.factory.state = 1 + self.state = 1 + self.newInstances(instdata, instances) + else: + if lastline: + self.lines += data + else: + self.lines += data+"\n" elif self.receiving == 2: - if data.startswith("ENDONTOLOGIES"): - instdata = self.lines - self.receiving = 0 - self.lines = "" - self.state = 2 - self.factory.state = 2 - self.loadOntologies(instdata) - self.factory.state = 1 - self.state = 1 - else: - if lastline: - self.lines += data - else: - self.lines += data+"\n" + if data.startswith("ENDONTOLOGIES"): + print " * ontologies received" + instdata = self.lines + self.receiving = 0 + self.lines = "" + self.state = 2 + self.factory.state = 2 + self.loadNamespaces(instdata) + self.factory.state = 1 + self.state = 1 + else: + if lastline: + self.lines += data + else: + self.lines += data+"\n" elif self.receiving == 3: - if data.startswith("ENDINIT"): - self.factory._proto = self - instdata = self.lines - self.receiving = 0 - self.lines = "" - self.state = 2 - self.factory.state = 2 - a = LoadModel(instdata,'DataSourceRoot', datasource=self.factory)[0] - self.server_uuid = a.uuid - self.server_node = a - for child in a.getChildren(): - self.factory.addChild(child) - self.factory.state = 1 - self.state = 1 - self.sendOntologies() - self.clientOK() - self.transport.write("INITOK\n") - else: - if lastline: - self.lines += data - else: - self.lines += data+"\n" + if data.startswith("ENDINIT"): + self.factory._proto = self + instdata = self.lines + self.receiving = 0 + self.lines = "" + self.state = 2 + self.factory.state = 2 + a = LoadModel(instdata,'DataSourceRoot', datasource=self.factory)[0] + self.server_uuid = a.uuid + self.server_node = a + for child in a.getChildren(): + self.factory.addChild(child) + self.factory.state = 1 + self.state = 1 + self.sendNamespaces() + self.clientOK() + self.transport.write("INITOK\n") + else: + if lastline: + self.lines += data + else: + self.lines += data+"\n" elif data.startswith("NEW"): self.receiving = 1 elif data.startswith("INIT:"): @@ -117,8 +138,13 @@ obj_uuid = vals[1] name = vals[2] val = LoadValue(vals[3]) - print " * pc:",name,val - self.setProperty(data,obj_uuid,name,val) + self.setProperty(data, obj_uuid, name, val) + elif data.startswith("REF:"): + vals = data.split(":",3) + obj_uuid = vals[1] + name = vals[2] + val_uuid = vals[3] + self.setReference(data, obj_uuid, name, val_uuid) elif data.startswith("ADDCHILD:"): vals = data.split(":") parent_uuid = vals[1] @@ -152,6 +178,9 @@ def setProperty(self, data, obj_uuid, name, val): pass + def setReference(self, data, obj_uuid, name, val_uuid): + pass + def addChild(self, data, parent, child): pass @@ -171,6 +200,14 @@ def sendPropertyChange(self, model, name, value): self.transport.write(PC(model, name, value)) + def sendReferenceChange(self, model, name, value): + value_uuid = str(value.uuid) + if not value_uuid in self.factory._instances: + data = SaveModel(value, datasource=self.factory) + self.transport.write("NEW\n"+data+"\nENDNEW\n") + self.factory._instances[value_uuid] = value + self.transport.write(REF(model, name, value)) + def sendNew(self, instance): data = SaveModel(instance, datasource=self.factory) self.transport.write("NEW\n"+data+"\nENDNEW\n") diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/twistedmm/server.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/twistedmm/server.py --- metamodel-0.1.1/metamodel/datasources/twistedmm/server.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/twistedmm/server.py 2009-12-09 13:50:28.000000000 +0000 @@ -1,7 +1,10 @@ +""" +Metamodel protocol 1 server +""" + import os -import uuid -from twisted.internet.protocol import Factory, Protocol +from twisted.internet.protocol import Factory from twisted.internet import reactor from twisted.internet.interfaces import IReactorSSL @@ -11,20 +14,20 @@ pass # XXX no ssl support! import metamodel -from metamodel.basemodel import SubscribableModel -from metamodel.properties import Property, File -from metamodel.datasources import DataSource, DataSourceRoot -from metamodel.yamlserializer import SaveModel, LoadModel, SaveValue - -from .proto import MetamodelProtocol1 -from .proto import PC, DEL, ADD, INV -from .guardian import InstanceGuardian -from .model import NetworkedModel +from metamodel import Property, File +from metamodel.datasources import DataSource +from metamodel.yamlserializer import SaveModel + +from proto import MetamodelProtocol1 +from proto import PC, DEL, ADD, INV +from guardian import InstanceGuardian class MetamodelServerProtocol1(MetamodelProtocol1): # connection state + transport = None + factory = None def connectionMade(self): - # send current world state + """ send current world state """ self.transport.write("INIT:\n") self.factory.serializeModel(self.factory, self.transport.write, inst_mapping={self.factory: "DataSourceRoot"}) @@ -35,9 +38,11 @@ self.factory.state = 1 def connectionLost(self, reason): + """ connection to client lost """ self.factory._clients.remove(self) def clientOK(self): + """ client finished initialization """ self.state = 1 self.factory.state = 1 @@ -48,9 +53,19 @@ self.sendToOthers(data+"\n") self.factory.state = 1 + def setReference(self, data, obj_uuid, name, val_uuid): + self.factory.state = 2 + val = self.factory._instances[val_uuid] + setattr(self.factory._instances[obj_uuid], name, val) + self.sendToOthers(data+"\n") + self.factory.state = 1 + def addChild(self, data, parent, child): if str(child.uuid) in self.factory._waitingparent: - child._datasource = parent._datasource # bad re-sourcing + if isinstance(parent, DataSource): + parent.own(child) # bad re-sourcing + else: + parent._datasource.own(child) # bad re-sourcing self.factory.state = 2 parent.addChild(child) self.factory.state = 1 @@ -90,6 +105,13 @@ def sendPropertyChange(self, model, name, value): self.sendToAll(PC(model, name, value)) + def sendReferenceChange(self, model, name, value): + value_uuid = str(value.uuid) + if not value in self._instances: + data = "NEW\n"+SaveModel(model, datasource=self, greedy=self.greedy)+"\nENDNEW\n" + self.sendToAll(data) + self.sendToAll(REF(model, name, value)) + def sendNew(self, instance): data = "NEW\n"+self.serializeModel(instance)+"\nENDNEW\n" self.sendToAll(data) @@ -110,17 +132,21 @@ class ServerInstanceGuardian(InstanceGuardian): def addchild(self, child): + print " - add foreign child",child self._datasource.add_foreign_child(child) - if not self._datasource.state == 1: return + if not self._datasource.state == 1: + return self._datasource.sendAddChild(self._model, child) def delchild(self, child): - if not self._datasource.state == 1: return + if not self._datasource.state == 1: + return self._datasource.sendDelChild(self._model, child) def invalidate(self): self._datasource.invalidate_foreign(self._model) - if not self._datasource.state == 1: return + if not self._datasource.state == 1: + return self._datasource.sendInvalidate(self._model) @@ -136,7 +162,7 @@ self.state = 0 active = None if "active" in kwargs: - active = kwargs.pop("active") + active = kwargs.pop("active") DataSource.__init__(self, *args, **kwargs) self._clients = [] self._instances = {} @@ -144,7 +170,7 @@ self._waitingparent = [] self._proto = self # hack so we can use the same instance guardian as the client if not active == None: - self.active = active + self.active = active self._instances[str(self.uuid)] = self # hook 'active' to activate the connection. note at the moment @@ -153,13 +179,17 @@ def setProperty(self, name, value): DataSource.setProperty(self, name, value) if name == "active" and value == True and not self.connected: - if self.port == 10111 and os.path.exists(self.key) and os.path.exists(self.certificate): - self._ctx = DefaultOpenSSLContextFactory(self.key, self.certificate) - reactorssl = IReactorSSL(reactor) - reactorssl.listenSSL(self.port, self, self._ctx) - else: - reactor.listenTCP(self.port, self) - self.connected = True + try: + if self.port == 10111 and os.path.exists(self.key) and os.path.exists(self.certificate): + self._ctx = DefaultOpenSSLContextFactory(self.key, self.certificate) + reactorssl = IReactorSSL(reactor) + reactorssl.listenSSL(self.port, self, self._ctx) + else: + reactor.listenTCP(self.port, self) + print "listenTCP",self.port + self.connected = True + except: + self.connected = False # hook up addChild and delChild to update the datasourceroot at # the same time @@ -182,6 +212,7 @@ self._instances[node_uuid] = node for child in node.getChildren(): self.add_foreign_child(child) + print "create guardian",node,str(node.uuid) self._guardians[node_uuid] = ServerInstanceGuardian(node, self) return True @@ -201,7 +232,7 @@ self._guardians[str(inst.uuid)] = ServerInstanceGuardian(inst, self) self._waitingparent.append(str(inst.uuid)) if self.state == 1: - self.sendNew(inst) + self.sendNew(inst) return inst def invalidate(self, node): diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/datasources/xmppsource.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/datasources/xmppsource.py --- metamodel-0.1.1/metamodel/datasources/xmppsource.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/datasources/xmppsource.py 2009-12-09 13:50:28.000000000 +0000 @@ -2,14 +2,12 @@ An xmpp datasource. """ -import os from collections import defaultdict +from metamodel import Property, Password from metamodel.basemodel import SubscribableModel -from metamodel.properties import Property,Password -from metamodel.yamlserializer import LoadModel, SaveModel -from metamodel.datasources import DataSource, DataSourceRoot +from metamodel.datasources import DataSource from twisted.words.protocols.jabber import client, jid, xmlstream from twisted.words.xish import domish @@ -20,12 +18,14 @@ from twisted.internet.interfaces import IReactorSSL from twisted.internet.ssl import ClientContextFactory -import wokkel -from wokkel import data_form, iwokkel, pubsub, shim, xmppim, disco, subprotocols +from wokkel import pubsub, xmppim, disco, subprotocols import uuid # xmpp model class XmppRosterItem(SubscribableModel): + """ + A roster item for an xmpp connection. + """ name = Property(str, "a contact") jid = Property(str, ro=True) available = Property(bool, False, ro=True) @@ -34,18 +34,30 @@ ask = Property(bool, False, ro=True) class XmppContactsModel(SubscribableModel): + """ + A contacts list for an xmpp connection. + """ name = Property(str, "contacts") class XmppDiscoModel(SubscribableModel): + """ + Discovery nodes. + """ name = Property(str, "disco") class XmppPubsubItem(SubscribableModel): + """ + A collection in a pubsub tree. + """ node = Property(str, "node") name = Property(str, "name") id = Property(str, "id") content = Property(str, "content") class ServiceInfoNode(SubscribableModel): + """ + An item in a pubsub tree. + """ name = Property(str, "disco") id = Property(str, "id", ro=True) node = Property(str, "disco", ro=True) @@ -62,11 +74,14 @@ # xmpp service datasource. # this is really just intended for pubsub, but used for other services atm. class XmppService(DataSource): + """ + An xmpp service. + """ def __init__(self, *args, **kwargs): DataSource.__init__(self, *args, **kwargs) def new(self, clsname, instance_uuid=None, *args, **kwargs): - inst = DataSource.new(self, clsname, instance_uuid=None, *args, **kwargs) + inst = DataSource.new(self, clsname, instance_uuid=instance_uuid, *args, **kwargs) if inst.__class__ == ServiceInfoNode and inst.published == False: PublishGuardian(inst) self._datasource._pubsubnodes[self.jid].append(inst) @@ -79,47 +94,50 @@ def invalidate(self, node): if isinstance(node, ServiceInfoNode): if not "!" in node.node: - d = self._datasource.pubsub.deleteNode(jid.JID(self.name),node.node) - d.addCallback(self.delete_done,node) + d = self._datasource.pubsub.deleteNode(jid.JID(self.name), node.node) + d.addCallback(self.delete_done, node) # XXX how to delete items? else: node.invalidate(True) - name = Property(str,"disco") - jid = Property(str,"jid",ro=True) - owner = Property(bool,False,ro=True) + name = Property(str, "disco") + jid = Property(str, "jid", ro=True) + owner = Property(bool, False, ro=True) # publish guardian. waits on new nodes for publishing. class PublishGuardian(object): + """ + Class to guard for publishing. + """ def __init__(self, model): model.subscribe(self) self._model = model - def propertychange(self,name,value): + def propertychange(self, name, value): if name == "published" and value == True: self._model.unsubscribe(self) self.publish() def publish(self): url = self._model._datasource.name - node = self._model._parents[0].node + node = self._model.getParents()[0].node content = self._model.content if content: item = domish.Element((None, 'item')) item.addRawXml(content) d = self._model._datasource._datasource.pubsub.publish(jid.JID(url), node, [item]) - d.addCallback(self.publish_done,node) + d.addCallback(self._publish_done, node) else: node = node+"/"+self._model.name - d = self._model._datasource._datasource.pubsub.createNode(jid.JID(url),node) - d.addCallback(self.new_done,node) + d = self._model._datasource._datasource.pubsub.createNode(jid.JID(url), node) + d.addCallback(self._new_done, node) - def new_done(self, item, nodepath): + def _new_done(self, item, nodepath): self._model.node = nodepath self._model.unsubscribe(self) - def publish_done(self, item, nodepath): + def _publish_done(self, item, nodepath): self._model.node = nodepath+"!UNKNOWN" self._model.name = self._model.content self._model.unsubscribe(self) @@ -129,7 +147,7 @@ # discovery information. class ServiceInfo(object): def __init__(self, model, name, protos, node="", url=""): - self._model = model + self.model = model self._name = name self._url = url self._node = node @@ -137,7 +155,7 @@ self._pubsub = protos[1] self._primed = False self._type = "" - model.subscribe(self) + self.model.subscribe(self) if not url: self._url = self._name else: @@ -145,40 +163,42 @@ self._nodes = {} # XXX nasty hack to do lazy expansion - model._getChildren = model.getChildren - model.getChildren = self.getChildChildren + self.model._getChildren = model.getChildren + self.model.getChildren = self.getChildChildren # subscription def propertychange(self, name, value): if name == "subscribed" and value == True: - servicejid = self._model._datasource.jid - nodeid = self._model.node - selfjid = self._model._datasource._datasource.jid - d = self._pubsub.subscribe(jid.JID(servicejid), nodeid, jid.JID(selfjid)) - s.addErrback(self.subscribe_failed) - s.addCallback(self.subscribe_succeeded) + servicejid = self.model._datasource.jid + nodeid = self.model.node + selfjid = self.model._datasource._datasource.jid + d = self._pubsub.subscribe(jid.JID(servicejid), nodeid, jid.JID(selfjid)) + d.addErrback(self.subscribe_failed) + d.addCallback(self.subscribe_succeeded) def subscribe_failed(self, *args): - self._model.subscribed = False + self.model.subscribed = False def subscribe_ok(self, *args): - self._model.subscribed = True + self.model.subscribed = True # invalidate model def invalidate(self): - self._model.unsubscribe(self) - self._model = False + self.model.unsubscribe(self) + self.model = False def getChildChildren(self): - self._model.getChildren = self._model._getChildren + self.model.getChildren = self.model._getChildren self.prime() - return self._model.getChildren() + return self.model.getChildren() # send initial discovery information request def prime(self): - if self._primed: return - if "!" in self._node: return - d = self._disco.requestInfo(jid.JID(self._url),self._node) + if self._primed: + return + if "!" in self._node: + return + d = self._disco.requestInfo(jid.JID(self._url), self._node) d.addCallback(self.discoInfoResponse) #d.addErrback(self.discoInfoError) @@ -187,60 +207,60 @@ return d def discoInfoError(self, failure): - print "discoInfoError",failure,dir(failure) + print "discoInfoError", failure, dir(failure) # get initial information, and request items def discoInfoResponse(self, items): for item in items: if item.name == "identity": - text = "IDENT"+" "+item["category"]+" "+item["type"] self._category = item["category"] atype = str(item["type"]) if self._type: self._type += ","+atype else: self._type += atype - try: - name=item["name"] - except: - name=item["category"] + #try: + # name=item["name"] + #except KeyError: + # name=item["category"] if item.name == "feature": - #self._model.addChild(self._model.new(XmppDiscoFeature,name=item["var"])) + #self.model.addChild(self.model.new(XmppDiscoFeature,name=item["var"])) pass - d = self._disco.requestItems(jid.JID(self._url),self._node) + d = self._disco.requestItems(jid.JID(self._url), self._node) d.addCallback(self.discoItemsResponse) #d.addErrback(self.discoItemsError) def discoItemsError(self, failure): - print "discoItemsError",failure + print "discoItemsError", failure # get disco items, and request pubsub items if its a leaf def discoItemsResponse(self, items): # separate services from pubsub nodes, create items for both for item in items: - protos = [self._disco,self._pubsub] + protos = [self._disco, self._pubsub] atype = self._type try: if "!" in item["node"]: atype="item" - m = self._model.new(ServiceInfoNode, + model = self.model.new(ServiceInfoNode, name=item["name"], node=item["node"], id=item["name"], published=True, type=atype, category=self._category) - self._model.addChild(m) - s = ServiceInfo(m,item["name"],protos,item["node"],self._url) - self._nodes[item["name"]] = s + self.model.addChild(model) + service = ServiceInfo(model, item["name"], protos, + item["node"], self._url) + self._nodes[item["name"]] = service except: - m = self._model.new(XmppService, - jid=item["jid"], - name=item["jid"]) - self._model.addChild(m) - s = ServiceInfo(m,item["jid"],protos) + model = self.model.new(XmppService, + jid=item["jid"], + name=item["jid"]) + self.model.addChild(model) + s = ServiceInfo(model, item["jid"], protos) if "leaf" in self._type: # "leaf": XXX pubsub get items doesnt work as expected - d = self._pubsub.items(jid.JID(self._url),self._node) + d = self._pubsub.items(jid.JID(self._url), self._node) d.addCallback(self.pubsubItemsResponse) d.addErrback(self.pubsubItemsError) @@ -248,7 +268,7 @@ def pubsubItemsError(self, failure): elmt = failure.value.getElement() if str(elmt["code"]) == "401" and str(elmt["type"]) == "auth": - self._model.owner = False + self.model.owner = False # get pubsub items def pubsubItemsResponse(self, items): @@ -256,17 +276,17 @@ for item in items: body = item.addContent("") if body.strip(): - self._nodes[item["id"]]._model.content = body - self._nodes[item["id"]]._model.name = body + self._nodes[item["id"]].model.content = body + self._nodes[item["id"]].model.name = body else: - self._nodes[item["id"]]._model.name = item.toXml() - self._nodes[item["id"]]._model.body = item.toXml() + self._nodes[item["id"]].model.name = item.toXml() + self._nodes[item["id"]].model.body = item.toXml() # data source class XmppDataSource(DataSource): - active = Property(bool,False) - usessl = Property(bool,False) + active = Property(bool, False) + usessl = Property(bool, False) name = Property(str, "an xmpp data source") server = Property(str, "delirium") password = Password() @@ -284,7 +304,9 @@ # relative to this one. self.contactsmodel = XmppContactsModel(uuid.uuid5(self.uuid, 'contacts'), self) self.discomodel = XmppDiscoModel(uuid.uuid5(self.uuid, 'disco'), self) - self.received = XmppDiscoModel(uuid.uuid5(self.uuid, 'received'), self, name="received") + self.received = XmppDiscoModel(uuid.uuid5(self.uuid, 'received'), + self, + name="received") self.addChild(self.contactsmodel) self.addChild(self.discomodel) self.addChild(self.received) @@ -294,7 +316,7 @@ self._pubsubnodes = defaultdict(list) # hook up on_uuid_set so we can update children uuids if uuid changes. if not active == None: - self.active = active + self.active = active self.on_uuid_set = self._on_uuid_set # DataSource operations @@ -304,8 +326,8 @@ self.received.uuid = uuid.uuid5(self.uuid, 'received') # Activate - def setProperty(self,name,value): - SubscribableModel.setProperty(self,name,value) + def setProperty(self, name, value): + SubscribableModel.setProperty(self, name, value) if name == "active": if value == False and self._connected: self.disconnectXmpp() @@ -325,9 +347,9 @@ """ Call this function to connect. """ - myJid = jid.JID(self.jid) + my_jid = jid.JID(self.jid) - factory = client.basicClientFactory(myJid, self.password) + factory = client.basicClientFactory(my_jid, self.password) self._fact = factory if self.usessl: self._ctx = ClientContextFactory() @@ -336,9 +358,9 @@ else: self._proto = reactor.connectTCP(self.server, self.port, self._fact) self.collection = subprotocols.StreamManager(factory) - factory.addBootstrap('//event/stream/authd',self.authd) - factory.addBootstrap(xmlstream.INIT_FAILED_EVENT,self.init_failed) - factory.addBootstrap(xmlstream.STREAM_END_EVENT,self.stream_end) + factory.addBootstrap('//event/stream/authd', self.authd) + factory.addBootstrap(xmlstream.INIT_FAILED_EVENT, self.init_failed) + factory.addBootstrap(xmlstream.STREAM_END_EVENT, self.stream_end) self._connected = True def init_failed(self, *args): @@ -383,12 +405,12 @@ self.disco = disco.DiscoClientProtocol() self.disco.setHandlerParent(self.collection) - self.createServiceModel(self.disco,self.pubsub) + self.createServiceModel(self.disco, self.pubsub) self.discomodel.getChildren() # dummy getchildren to trigger discovery - def createServiceModel(self,disco,pubsub): - s = ServiceInfo(self.discomodel, self.server, [disco,pubsub]) + def createServiceModel(self, disco, pubsub): + service = ServiceInfo(self.discomodel, self.server, [disco, pubsub]) # PubSub events def processItems(self, items, parentnode, nodeIdentifier): @@ -409,34 +431,35 @@ def itemsReceived(self, event): servicejid = event.sender.full() if servicejid in self._pubsubnodes: - parentnodes = filter(lambda s: s.node == event.nodeIdentifier, + parentnodes = filter(lambda s: s.node == event.nodeIdentifier, self._pubsubnodes[servicejid]) - if parentnodes: - self.processItems(event.items, parentnodes[0], event.nodeIdentifier) - # else: dont throw away... XXX + if parentnodes: + self.processItems(event.items, parentnodes[0], event.nodeIdentifier) + # else: dont throw away... XXX # else: dont throw away... XXX def deleteReceived(self, event): servicejid = sender.full() - print "DELETE RECEIVED!",servicejid + print "DELETE RECEIVED!", servicejid if servicejid in self._pubsubnodes: - nodes = filter(lambda s: s.node == event.nodeIdentifier, self._pubsubnodes[servicejid]) + nodes = filter(lambda s: s.node == event.nodeIdentifier, + self._pubsubnodes[servicejid]) for node in nodes: self._pubsubnodes[servicejid].remove(node) self._pubsubnodes[servicejid].invalidate(True) def purgeReceived(self, event): - print "purge",event + print "purge", event # Presence Events def availableReceived(self, entity, show=None, statuses=None, priority=0): userjid = entity.userhost() if not userjid in self._contacts: - rosteritem = self.contactsmodel.new(XmppRosterItem, + rosteritem = self.contactsmodel.new(XmppRosterItem, name=entity.userhost(), jid=entity.full()) - self._contacts[userjid] = rosteritem - self.contactsmodel.addChild(rosteritem) + self._contacts[userjid] = rosteritem + self.contactsmodel.addChild(rosteritem) self._contacts[userjid].available = True def unavailableReceived(self, entity, statuses=None): @@ -446,23 +469,23 @@ def rosterArrived(self, roster): for item in roster.values(): - jid = item.jid.full() - userjid = item.jid.userhost() - if item.name: - name = item.name - else: - name = jid - if not userjid in self._contacts: - rosteritem = self.contactsmodel.new(XmppRosterItem, - name=userjid, - jid=jid) - self._contacts[userjid] = rosteritem - self.contactsmodel.addChild(rosteritem) - else: - rosteritem = self._contacts[userjid] - rosteritem.subscriptionTo = item.subscriptionTo - rosteritem.subscriptionFrom = item.subscriptionFrom - rosteritem.ask = item.ask + jid = item.jid.full() + userjid = item.jid.userhost() + if item.name: + name = item.name + else: + name = jid + if not userjid in self._contacts: + rosteritem = self.contactsmodel.new(XmppRosterItem, + name=userjid, + jid=jid) + self._contacts[userjid] = rosteritem + self.contactsmodel.addChild(rosteritem) + else: + rosteritem = self._contacts[userjid] + rosteritem.subscriptionTo = item.subscriptionTo + rosteritem.subscriptionFrom = item.subscriptionFrom + rosteritem.ask = item.ask def sendPresence(self): pres = xmppim.Presence() diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/dictserializer.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/dictserializer.py --- metamodel-0.1.1/metamodel/dictserializer.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/dictserializer.py 2009-12-09 13:50:29.000000000 +0000 @@ -4,98 +4,127 @@ import uuid -from .meta import ClassRegistry -from .basemodel import SubscribableModel,UnknownModel -from .instancereg import ChildWaiter,PropWaiter - -def FindUUID(obj_uuid): +from meta import ClassRegistry +from basemodel import SubscribableModel, UnknownModel +from instancereg import ChildWaiter, PropWaiter + +def find_uuid(obj_uuid): + """ + Find the object with a certain uuid. + """ for klass in ClassRegistry.values(): + # check _instances because we want only the + # instances for this class. for inst in klass._instances: try: if inst.uuid == obj_uuid: - return inst - except: + return inst + except AttributeError: pass -def WaitForClass(clsname, objid, obj, reqclsname, datasource): - def wait(klass): +def wait_for_class(clsname, objid, obj, reqclsname, datasource): + """ + Wait for the given class to appear. + """ + def wait(_): LoadModel({objid:obj}, reqclsname, datasource) ClassRegistry.subscribe(wait, clsname) +def check_unref_properties(tounref, objects): + """ + Check for properties which can be unrefed to this object. + """ + # unref properties + for newobj2, prop, val in tounref: + try: + val = objects[val] + except KeyError: + obj = find_uuid(uuid.UUID(val)) + if obj: + objects[val] = obj + val = obj + else: + PropWaiter(uuid.UUID(val), newobj2, prop) + val = UnknownModel() + setattr(newobj2, prop, val) + +def check_unref_children(unrefchilds, objects): + """ + Check for objects which have to be connected to this one. + """ + # unref children + for newobj, children in unrefchilds: + for child in children: + try: + newobj.addChild(objects[child]) + except KeyError: + obj = find_uuid(uuid.UUID(child)) + if obj: + objects[child] = obj + newobj.addChild(obj) + else: + ChildWaiter(uuid.UUID(child), newobj) + def LoadModel(objs, reqclsname=None, datasource=None): + """ + Convert given dict model into metamodel classes. + """ retobj = [] objects = {} tounref = [] unrefchilds = [] # load objects - for objid,obj in objs.iteritems(): - clsname,objuuid = objid.split("#") + for objid, obj in objs.iteritems(): + clsname, objuuid = objid.split("#") if not clsname in ClassRegistry: - WaitForClass(clsname, objid, obj, reqclsname, datasource) + wait_for_class(clsname, objid, dict(obj), reqclsname, datasource) continue cls = ClassRegistry[clsname] objunref = [] kwargs = {} children = obj.pop("children") - for prop,value in obj.iteritems(): + for prop, value in obj.iteritems(): if isinstance(value, str) and value.startswith("uuid:"): try: value = objects[value[5:]] kwargs[prop] = value - except: - objunref.append([prop,value[5:]]) + except KeyError: + objunref.append([prop, value[5:]]) else: kwargs[prop] = value if datasource: newobj = datasource.new(cls, uuid.UUID(objuuid), **kwargs) else: newobj = cls(uuid.UUID(objuuid), **kwargs) + # append the references needing unrefing for prop, val in objunref: tounref.append([newobj, prop, val]) + # check if its in the class requested if reqclsname and clsname == reqclsname: retobj.append(newobj) objects[objuuid] = newobj + # add the childs for unrefing if len(children): - unrefchilds.append([newobj,children]) - # publish object: - #newobj.uuid = uuid.UUID(objuuid) - # unref properties - for newobj2,prop,val in tounref: - try: - val = objects[val] - except: - obj = FindUUID(uuid.UUID(val)) - if obj: - objects[val] = obj - val = obj - else: - PropWaiter(uuid.UUID(val), newobj2, prop) - val = UnknownModel() - setattr(newobj2,prop,val) - # unref children - for newobj,children in unrefchilds: - for child in children: - try: - newobj.addChild(objects[child]) - except: - obj = FindUUID(uuid.UUID(child)) - if obj: - objects[child] = obj - newobj.addChild(obj) - else: - ChildWaiter(uuid.UUID(child),newobj) + unrefchilds.append([newobj, children]) + # unref or produce waiters + check_unref_properties(tounref, objects) + check_unref_children(unrefchilds, objects) return retobj def SaveModel(model): + """ + Convert given model into a dict. + """ # prepare struct - props = { "children" : map(lambda s: str(s.uuid), model.getChildrenToPersist()) } + props = { "children" : map(lambda s: str(s.uuid), + model.getChildrenToPersist()) } obj = {str(model.__class__.__name__)+"#"+str(model.uuid): props} - # dereference properties - for prop,value in model._props.iteritems(): - if not model.isDefault(prop): - if isinstance(value,SubscribableModel): - props[prop] = "uuid:"+str(value.uuid) - else: - props[prop] = value + # dereference properties, the ones in the internal dictionary are + # the ones assumed to be set. + for prop, value in model._props.iteritems(): + if isinstance(value, SubscribableModel): + props[prop] = "uuid:"+str(value.uuid) + else: + props[prop] = value return obj diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/dynamicmeta.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/dynamicmeta.py --- metamodel-0.1.1/metamodel/dynamicmeta.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/dynamicmeta.py 2009-12-09 13:50:28.000000000 +0000 @@ -1,15 +1,16 @@ """ Dynamic class and instance synchronization against the ontology model. -Maintains a set of python classes accessible through metamodel.RegistryView.. +Maintains a set of python classes accessible through +metamodel.RegistryView.. """ -from .basemodel import SubscribableModel -from .metamodel import MetaProperty, MetaModel, Ontology -from .properties import Property -from .meta import SubscribableModelMeta, ClassRegistry -from .yamlserializer import SaveModel, LoadModel -from .baseview import ViewObjectBase, ModelViewBase +from basemodel import SubscribableModel +from metamodel import MetaProperty, MetaModel, Namespace +from properties import Property, Vector3, Vector2, Color, Color4 +from meta import SubscribableModelMeta, ClassRegistry +from yamlserializer import LoadModel +from baseview import ViewObjectBase, ModelViewBase class PropertyGuardian(ViewObjectBase): """ @@ -26,108 +27,134 @@ self._default = model.default def create_property(self, model): - k = ClassRegistry[self._parents[0].classname] # XXX _parents use - if model.name in k.properties: + """ + Create some property in the guarded python class. + """ + klass = ClassRegistry[self._parents[0].classname] # XXX _parents use + if model.name in klass.properties: return - proptype = eval(model.type) - try: - if proptype == bool: - if model.default in ["False","false","no","0"]: - default = False - else: - default = True - elif proptype == list: - default = eval(model.default) - else: - default = proptype(model.default) - except: - default = None - prop = Property(proptype, default) + propclass = Property + propmap = {"Vector3": Vector3, "Vector2": Vector2, "Color4": Color4, + "Color": Color} + if model.type in propmap: + propclass = propmap[model.type] + default = eval(model.default) + else: + try: + proptype = eval(model.type) + try: + if proptype == bool: + if model.default in ["False", "false", "no", "0"]: + default = False + else: + default = True + elif proptype == list: + default = eval(model.default) + else: + default = proptype(model.default) + except: + default = None + except: + proptype = ClassRegistry[model.type] + default = None + if propclass == Property: + prop = Property(proptype, default) + else: + prop = propclass() prop.name = model.name - k.properties.append(model.name) - for a in k._instances: - a.properties.append(model.name) - setattr(k, model.name, prop) - if not default == None: - for a in k._instances: - setattr(a, model.name, default) + klass.properties.append(model.name) + setattr(klass, model.name, prop) + for inst in klass.get_instances(): + if prop.name in inst._props: + value = inst._props[prop.name] + else: + value = default + if not value == None: + inst._post_evh("propertychange", prop.name, value) + inst._post_signal(prop.name, value) + # inst.properties.append(model.name) + #if not default == None: + # for inst in klass.get_instances(): + # setattr(inst, model.name, default) def invalidate(self): - k = ClassRegistry[self._parents[0].classname] # XXX _parents use - for a in k._instances: - a.delProperty(self._model.name) + """ + Invalidate callback + """ + klass = ClassRegistry[self._parents[0].classname] # XXX _parents use + for inst in klass.get_instances(): + inst.delProperty(self._model.name) # destroy in class - delattr(k, self._model.name) + delattr(klass, self._model.name) - def change_name(self,value): + def change_name(self, value): """ the property changed name """ if value == self._name: return - k = ClassRegistry[self._parents[0].classname] # XXX _parents use - k.properties.remove(self._name) + klass = ClassRegistry[self._parents[0].classname] # XXX _parents use + klass.properties.remove(self._name) prop = Property(eval(self._model.type), self._model.default) prop.name = value # create the new property in the class - setattr(k,value,prop) + setattr(klass, value, prop) # recreate properties at instances - for a in k._instances: - oldval = getattr(a,self._name) - # create new property - setattr(a,value,oldval) - a.delProperty(self._name) + for inst in klass._instances: + oldval = getattr(inst, self._name) + # create new property + setattr(inst, value, oldval) + inst.delProperty(self._name) # remove old property - delattr(k,self._name) + delattr(klass, self._name) # set some extra info - k.properties.append(value) + klass.properties.append(value) self._name = value - def change_default(self,value): + def change_default(self, value): """ the property changed default adapt defaults. """ - k = ClassRegistry[self._parents[0].classname] # XXX parents use - p = getattr(k,self._name) - for a in k._instances: - oldval = getattr(a,self._name) - if oldval == self._default: - # reset XXX not sure this is best.. - #print " * apply change",oldval,"-->",self._name,value,value.__class__ - setattr(a,self._name,value) - p._default = value + klass = ClassRegistry[self._parents[0].classname] # XXX parents use + prop = getattr(klass, self._name) + for inst in klass._instances: + oldval = getattr(inst, self._name) + if oldval == self._default: + # reset XXX not sure this is best.. + setattr(inst, self._name, value) + prop.default = value self._default = value - def change_type(self,value): + def change_type(self, value): """ the property changed type adapt values in instances, adapt default. """ k = ClassRegistry[self._parents[0].classname] # XXX parents use - p = getattr(k,self._name) + prop = getattr(k, self._name) # change type - p._proptype = eval(value) + prop.type = eval(value) # correct default try: # try to convert - newdefault = p._proptype(self._default) + newdefault = prop.type(self._default) except: # else default to empty constructor for declared type - newdefault = p._proptype() + newdefault = prop.type() # set default self._model.default = newdefault # pass - for a in k._instances: - oldval = getattr(a,self._name) + for inst in k._instances: + oldval = getattr(inst, self._name) #print "apply change type:",oldval try: - newval = p._proptype(oldval) - except: - newval = p._default - setattr(a,self._name,newval) + newval = prop.type(oldval) + except ValueError: + newval = prop.default + setattr(inst, self._name, newval) self._type = value # properties reacting to the model's properties. @@ -159,7 +186,7 @@ for parent in model.inheritfrom: parents += (ClassRegistry[parent],) if not parents: - parents = (SubscribableModel,) + parents = (SubscribableModel,) dct["builds"] = model.builds_list dct["builtby"] = model.builtby_list klass = SubscribableModelMeta.__new__(SubscribableModelMeta, @@ -169,13 +196,44 @@ model) klass._model = model # XXX just for the test :P ClassRegistry[model.name] = klass + namespaces = self.findClassNamespaces() + for ns in namespaces: + ClassRegistry[ns+"."+model.name] = klass return klass + def findClassNamespaces(self): + namespaces = [] + parents = [] + model = self._model + parent_nss = filter(lambda s: isinstance(s, Namespace), model.getParents()) + for parent_ns in parent_nss: + parents = self._findParentNS([parent_ns], []) + for parent in parents: + parent_names = map(lambda s: s.name, parent) + namespaces.append(".".join(parent_names)) + return namespaces + + def _findParentNS(self, path, stack): + all_parents = [] + ns = path[0] + parent_nss = filter(lambda s: isinstance(s, Namespace), ns.getParents()) + if parent_nss: + for parent_ns in parent_nss: + parent_path = [parent_ns] + path + parents = self._findParentNS(parent_path, []) + all_parents += parents + else: + all_parents = [path] + return all_parents + def invalidate(self): + """ + Invalidate callback. + """ print "ClassGuardian::invalidate not implemented!" -class OntologyGuardian(ViewObjectBase): +class NamespaceGuardian(ViewObjectBase): """ Guards an ontology. @@ -188,7 +246,7 @@ """ Main model to hold all ontologies. """ - builds = ["Ontology"] + builds = ["Namespace"] class InstanceRegistry(ModelViewBase): @@ -198,15 +256,15 @@ Can load a number of ontologies from disk. """ _model2view = { - "Ontology" : [OntologyGuardian], + "Namespace" : [NamespaceGuardian], "MetaModel" : [ClassGuardian], "MetaProperty" : [PropertyGuardian], } def __init__(self, model): ModelViewBase.__init__(self, model) - self.internalOntology = self._model.new(Ontology, name="internal") - self._model.addChild(self.internalOntology) + self._internalNamespace = self._model.new(Namespace, name="internal") + self._model.addChild(self._internalNamespace) def createClassModel(self, cls): """ @@ -214,9 +272,9 @@ """ bases = [] for base in cls.__bases__: - if issubclass(base,SubscribableModel) and not base == cls: - bases.append(base.__name__) - class_meta = self._model.new(MetaModel,classname=cls.__name__, + if issubclass(base, SubscribableModel) and not base == cls: + bases.append(base.__name__) + class_meta = self._model.new(MetaModel, classname=cls.__name__, name=cls.__name__, inherit_from=bases, builtby_list=list(cls.builtby), @@ -224,33 +282,46 @@ for propname in dir(cls): try: prop_obj = getattr(cls, propname) - except: - pass + except AttributeError: + continue if isinstance(prop_obj, Property): - metaprop = self._model.new(MetaProperty,name=prop_obj.name, - type=prop_obj._proptype.__name__, - ro=prop_obj._ro) - if not prop_obj._default == None: - metaprop.default = str(prop_obj._default) - class_meta.addChild(metaprop) - self.internalOntology.addChild(class_meta) + metaprop = self._model.new(MetaProperty, name=prop_obj.name, + type = prop_obj.type.__name__, + ro = prop_obj.ro) + if not prop_obj._default == None: + metaprop.default = str(prop_obj._default) + class_meta.addChild(metaprop) + namespacename = cls.__module__ + ont = self.createNamespaces(namespacename) + ont.addChild(class_meta) return class_meta + def createNamespaces(self, namespacename): + splitname = namespacename.split('.') + currparent = self._model + while splitname: + ont = currparent.findChild(splitname[0]) + if not ont: + ont = currparent.new(Namespace, name=splitname[0]) + currparent.addChild(ont) + currparent = ont + splitname.pop(0) + return ont + def __getattr__(self, name): """ Implements attribute access for instanced classes. """ return ClassRegistry[name] - - def load_file(self, file): + def load_file(self, filename): """ load a file with ontology data """ - f = open(file) - data = f.read() - f.close() - ontologies = LoadModel(data,"Ontology") + afile = open(filename) + data = afile.read() + afile.close() + ontologies = LoadModel(data,"Namespace") for ontology in ontologies: self._model.addChild(ontology) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/filters/__init__.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/filters/__init__.py --- metamodel-0.1.1/metamodel/filters/__init__.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/filters/__init__.py 2009-12-09 13:50:28.000000000 +0000 @@ -2,7 +2,7 @@ Filters are nodes which syndicate other models. """ -from ..basemodel import SubscribableModel +from metamodel.basemodel import SubscribableModel class Filter(SubscribableModel): pass diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/hierarview.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/hierarview.py --- metamodel-0.1.1/metamodel/hierarview.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/metamodel/hierarview.py 2009-12-09 13:50:29.000000000 +0000 @@ -0,0 +1,159 @@ +from collections import defaultdict + + +class HierarView(object): + """ + The goal of this view is to achieve a tree of responsabilities. + + + Any node, subnode, subsubnode, etc of a HierarView are managed by + it. + + When another HierarView is encountered in the tree, this one + becomes responsible for all its subnodes. + + TopModel [TopView] + `-- ModelA + `-- ModelA1 + `-- ModelB [BView] + `-- ModelB1 + + Here, TopView manages TopModel, ModelA and ModelA1 while BView + manages ModelB and ModelB1. + """ + _model2view = {} + + def __init__(self, aModel, aParentModel=None, aParentView=None, + theTopView=None): + self._children_views = {} + self._top_view = theTopView + self._model = aModel + self._parent_view = aParentView + self._parent_model = aParentModel + + aModel.subscribe(self) + + for child in aModel.getChildren(): + self._traverse(child, aModel) + + def _instanciate_view(self, aModel, aParentModel): + """ + Try to instanciate a view for a given model. + """ + class_name = aModel.__class__.__name__ + + # Try to mimic polymorphism using MROs + if not class_name in self._model2view: + parents = map(lambda s: s.__name__, aModel.__class__.__mro__) + orig = parents.pop() # pop ourselves + class_name = parents.pop() # pop first parent + while parents and not class_name in self._model2view: + class_name = parents.pop() + if not class_name in self._model2view: + return False + + self._model2view[orig] = self._model2view[class_name] + + # Instanciate view(s) + for view_class in self._model2view[class_name]: + new_view = None + if self._top_view: + new_view = self._top_view.getViewNode(aModel) + if not new_view: + new_view = view_class(aModel, aParentModel, self, self._top_view) + if self._top_view: + self._top_view.addViewNode(aModel, new_view) + self._children_views[aModel.uuid] = new_view + + return True + + def _traverse(self, aModel, aParentModel): + """ + Traverse, mirror and subscribe to a model. + """ + # if we find a nested view, delegate work and return + if self._instanciate_view(aModel, aParentModel): + return + + aModel.subscribe(self) + for child in aModel.getChildren(): + self._traverse(child, aModel) + + def _removeBranch(self, aModel): + """ + Remove a branch from the view in reaction to a model branch + removal (normally you remove the model instead). + """ + if aModel.uuid in self._children_views: + for child in aModel.getChildren(): + self._removeBranch(child) + + self._children_views[aModel.uuid].unlink() + if self._top_view: + self._top_view.delViewNode(aModel) + del self._children_views[aModel.uuid] + + #-- Model callbacks --# + def propertychange(self, aName, aValue): + """ + Called when a property is changed in the model + """ + if hasattr(self.__class__, aName): + setattr(self, aName, aValue) + + def addchild(self, aModel): + """ + Called when a child is added to a watched model + """ + # FIXME: This is wrong, the parent is not always our root model ! + self._traverse(aModel, self._model) + + def delchild(self, aModel): + """ + Called when a child is removed from our tree + """ + self._removeBranch(aModel) + + #-- View Callbacks --# + def addparent(self, parent): + """ + Add a parent node to this object. + """ + self._parents.append(parent) + + def unlink(self): + """ + Object unlinked from some parents. + """ + pass + + + +class TopHierarView(HierarView): + """ + Mandatory root node for a hierarchical view graph. + """ + def __init__(self, aModel, aParentModel=None, aParentView=None): + self._view_registry = {} + HierarView.__init__(self, aModel, theTopView=self) + + def addViewNode(self, model, view): + """ + Add a view node to the view. + """ + self._view_registry[model.uuid] = view + + def delViewNode(self, model): + """ + Delete a view node from the view. + """ + del self._view_registry[model.uuid] + + + def getViewNode(self, model): + """ + Get the view node instantiated for the given model. + """ + return self._view_registry.get(model.uuid, None) + + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/__init__.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/__init__.py --- metamodel-0.1.1/metamodel/__init__.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/__init__.py 2009-12-09 13:50:29.000000000 +0000 @@ -2,9 +2,17 @@ import metamodel import dynamicmeta import datasources +import properties from basemodel import SubscribableModel from properties import Property, SingleChoice, Color, Color4, Vector2, Vector3, Vector4, Link, Password, File from datasources import DataSource, Folder from meta import ClassRegistry +class TestClass(SubscribableModel): + name = Property(str, 'name') + testprop = Property(str, '') + testprop2 = Property(str, '') + + + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/instancereg.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/instancereg.py --- metamodel-0.1.1/metamodel/instancereg.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/instancereg.py 2009-12-09 13:50:29.000000000 +0000 @@ -8,13 +8,23 @@ import uuid from collections import defaultdict -from meta import SubscribableModelMeta,ClassRegistry +from meta import SubscribableModelMeta, ClassRegistry class _InstanceRegistry(object): def __init__(self): self._listeners = defaultdict(list) self._global_listeners = [] + def replace_listener(self, old_listener, new_listener): + for listener in list(self._global_listeners): + if hasattr(listener, "_obj") and listener._obj == old_listener: + listener._obj = new_listener + for section in self._listeners: + section_list = self._listeners[section] + for listener in section_list: + if hasattr(listener, "_obj") and listener._obj == old_listener: + listener._obj = new_listener + def subscribe(self, listener, uuid=None): if uuid: self._listeners[uuid].append(listener) @@ -36,22 +46,22 @@ Base class for something that waits until an instance is present to fill in a property. """ - def __init__(self,uuid,obj,prop): - InstanceRegistry.subscribe(self,uuid) + def __init__(self, uuid, obj, prop): + InstanceRegistry.subscribe(self, uuid) self._obj = obj self._prop = prop - def uuidInstanced(self,obj): - setattr(self._obj,self._prop,obj) + def uuidInstanced(self, obj): + setattr(self._obj, self._prop, obj) class ChildWaiter(object): """ Base class for something that waits until an instance is present to add a child. """ - def __init__(self,uuid,obj): - InstanceRegistry.subscribe(self,uuid) + def __init__(self, uuid, obj): + InstanceRegistry.subscribe(self, uuid) self._obj = obj - def uuidInstanced(self,obj): + def uuidInstanced(self, obj): self._obj.addChild(obj) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/messaging.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/messaging.py --- metamodel-0.1.1/metamodel/messaging.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/metamodel/messaging.py 2009-12-09 13:50:29.000000000 +0000 @@ -0,0 +1,8 @@ +from metamodel import SubscribableModel, Property + +class Signal(SubscribableModel): + name = Property(str, 'a signal') + +class Socket(SubscribableModel): + name = Property(str, 'a socket') + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/metamodel.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/metamodel.py --- metamodel-0.1.1/metamodel/metamodel.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/metamodel.py 2009-12-09 13:50:28.000000000 +0000 @@ -2,15 +2,15 @@ Model for model description. """ -from .basemodel import SubscribableModel +from basemodel import SubscribableModel -from .properties import Property +from properties import Property -class OntologiesModel(SubscribableModel): +class NamespaceFolder(SubscribableModel): """ Dummy model that creates ontologies. """ - builds = ["Ontology"] + builds = ["Namespace"] class MetaProperty(SubscribableModel): """ @@ -35,11 +35,11 @@ builds = ["MetaProperty"] -class Ontology(SubscribableModel): +class Namespace(SubscribableModel): """ A set of classes. """ - name = Property(str,"Unnamed Ontology") + name = Property(str,"Unnamed Namespace") - builds = ["MetaModel"] + builds = ["MetaModel", "Namespace"] diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/meta.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/meta.py --- metamodel-0.1.1/metamodel/meta.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/meta.py 2009-12-09 13:50:28.000000000 +0000 @@ -3,23 +3,32 @@ """ from collections import defaultdict -from .properties import Property +from properties import Property -#: Class registry. All classes in the system can be queried here by name. class _ClassRegistry(object): + """ + Class registry. All classes in the system can be queried here by name. + """ def __init__(self): self._values = {} self._listeners = defaultdict(list) self._global_listeners = [] def subscribe(self, listener, name=None): + """ + Subscribe to a certain class appearing, or to all classes + if name is None. + """ if name: self._listeners[name].append(listener) else: self._global_listeners.append(listener) def post(self, name, obj): + """ + Post a certain class appearing in the registry. + """ for listener in self._global_listeners: listener(obj) if name in self._listeners: @@ -28,11 +37,15 @@ del self._listeners[name] def values(self): + """ + Get all values in the registry. + """ return self._values.values() def __setitem__(self, key, value): + self._values[value.__module__+'.'+key] = value self._values[key] = value - self.post(key, value) + #self.post(key, value) def __contains__(self, key): return self._values.__contains__(key) @@ -41,8 +54,8 @@ return self._values[key] def __iter__(self): - for a in self._values: - yield a + for value in self._values: + yield value ClassRegistry = _ClassRegistry() _ChildInfo = defaultdict(set) @@ -50,7 +63,6 @@ _PendingBuilderInfo = defaultdict(set) _PendingBuiltbyInfo = defaultdict(set) - class SubscribableModelMeta(type): """ Metaclass for subscribable models. @@ -58,21 +70,23 @@ Fills in some property and relation information, registers the class, and provides some api for the class. """ - def createClassModel(cls): + def createClassModel(mcs): + """ + Create the mm model for a python class. + """ try: - from .dynamicmeta import RegistryView - except: - # print "cant create model:",cls.__name__ + from dynamicmeta import RegistryView + except ImportError: # this is normal for the first "core" models, which have to be # created for the dynamic meta runtime to exist. return - #traceback.print_exc() - return RegistryView.createClassModel(cls) - def __new__(cls, name, bases, dct, model=None): + return RegistryView.createClassModel(mcs) + + def __new__(mcs, name, bases, dct, model=None): if not "abstract" in dct: dct["abstract"] = False - acls = type.__new__(cls, name, bases, dct) + acls = type.__new__(mcs, name, bases, dct) ClassRegistry[name] = acls # save parents and childrens matrix @@ -81,18 +95,18 @@ _ChildInfo[base.__name__].add(name) for aparent in _ParentInfo[base.__name__]: _ChildInfo[aparent].add(name) - - # XXX some uglyness to avoid putting the name in the + + # some uglyness to avoid putting the name in the # Property constructor. acls._instances = [] acls.properties = [] for propname in dir(acls): try: - obj = getattr(acls,propname) - except: + obj = getattr(acls, propname) + except AttributeError: # its fine, some properties are write only continue - if isinstance(obj,Property): + if isinstance(obj, Property): obj.name = propname acls.properties.append(propname) @@ -129,41 +143,45 @@ if not model: model = acls.createClassModel() acls._model = model + ClassRegistry.post(name, acls) return acls - def get_builds(cls): + def get_builds(mcs): """ Get the list of models building this model. """ builds = set() - for acls in cls.__mro__: + for acls in mcs.__mro__: try: builds = builds.union(acls.builds) - except: - pass + except AttributeError: # to avoid 'object' root + continue for build in list(builds): childs = _ChildInfo[build] builds = builds.union(childs) return builds - def get_builtby(cls): + def get_builtby(mcs): """ Get the list of built models for this model. """ builds = set() - for acls in cls.__mro__: + for acls in mcs.__mro__: try: builds = builds.union(acls.builtby) - except: - pass + except AttributeError: # to avoid 'object' root + continue for build in list(builds): childs = _ChildInfo[build] builds = builds.union(childs) return builds - def get_instances(cls): - instances = list(cls._instances) - for acls in _ChildInfo[cls.__name__]: - instances+=ClassRegistry[acls]._instances + def get_instances(mcs): + """ + Get all instances for this class. + """ + instances = list(mcs._instances) + for acls in _ChildInfo[mcs.__name__]: + instances += ClassRegistry[acls]._instances return instances diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/overlay.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/overlay.py --- metamodel-0.1.1/metamodel/overlay.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/overlay.py 2009-12-09 13:50:29.000000000 +0000 @@ -5,8 +5,8 @@ with the underlying model. """ -from .basemodel import SubscribableModel -from .properties import Property +from basemodel import SubscribableModel +from properties import Property ####################################################################### # Node Watcher @@ -22,8 +22,8 @@ self._overlay = overlay self._origmodel = origmodel self._origmodel.subscribe(self) - self._properties = dict(self._origmodel._props) self._state = 1 + self._props = {} def pushChanges(self): """ @@ -38,21 +38,25 @@ neworig = child.deepclone() self._origmodel.addChild(neworig) self._stack[neworig] = child - self._overlay._watchers[neworig] = _NodeWatcher(self._overlay, self._stack, child, neworig) + watchers = self._overlay._watchers + watchers[neworig] = _NodeWatcher(self._overlay, + self._stack, + child, + neworig) else: # still there - for o,d in self._stack.items(): + for o, d in self._stack.items(): if d == child: origchildren.remove(o) # remove nodes which have been deleted for remaining in origchildren: self._origmodel.delChild(remaining) # sync properties - for prop in self._model.properties: + for prop in self._model._props: newval = getattr(self._model, prop) if not getattr(self._origmodel, prop) == newval: setattr(self._origmodel, prop, newval) - self._properties[prop] = newval + self._model._props = {} self._state = 1 def overlay_deepclone(self, elmt): @@ -73,15 +77,14 @@ """ A property changed in the upstream model. """ - if getattr(self._model, name) == self._properties[name]: - setattr(self._model, name, value) - self._properties[name] = value + return def addchild(self, child): """ A child was added in the upstream model. """ - if not self._state: return + if not self._state: + return clonedchild = self.overlay_deepclone(child) if not clonedchild in self._model.getChildren(): self._model.addChild(clonedchild) @@ -90,7 +93,8 @@ """ A child was deleted from the upstream model. """ - if not self._state: return + if not self._state: + return clonedchild = self._stack[child] self._model.delChild(clonedchild) @@ -110,7 +114,7 @@ """ Root for the mappings from an overlay. """ - nchildren = Property(int,0) + nchildren = Property(int, 0) class OverlayMap(SubscribableModel): """ @@ -126,7 +130,7 @@ model = Property(SubscribableModel) shadow = Property(SubscribableModel) mapping = Property(SubscribableModel) - def __init__(self, instance_uuid=None, datasource=None, topersist=False, **kwargs): + def __init__(self, instance_uuid=None, datasource=None, topersist=0, **kwargs): self._state = 0 self._topersist = topersist self._setprops = set() @@ -138,7 +142,7 @@ else: self.mapping.subscribe(self) - def addchild(self, child): + def addchild(self, _): """ This function waits until mappings are filled up on loading. """ @@ -150,13 +154,19 @@ """ Become an overlay now. """ - if self._topersist: return + if self._topersist: + return self._state = 0 shadow = self.shadow mapping = self.mapping model = self.model self.__class__ = Overlay - Overlay.__init__(self, self.uuid, datasource=self._datasource, model=model, shadow=shadow, mapping=mapping) + Overlay.__init__(self, + self.uuid, + datasource=self._datasource, + model=model, + shadow=shadow, + mapping=mapping) def setProperty(self, name, val): """ @@ -224,6 +234,7 @@ self.pushChanges = self._pushChanges self.getChildren = self._getChildren self.getOverlayModel = self._getOverlayModel + self.getOverlayInstance = self._getOverlayInstance self.getSelfToPersist = self._getSelfToPersist self.clone = self._clone self.deepclone = self._deepclone @@ -232,7 +243,7 @@ self.__class__._instances.append(self) # publish ourselves with our class # hook overlay model core SubscribableModel properties on ourselves. self._children = self._instance._children - self._props = self._instance._props + self._props = {} #self._instance._props self._evhs = self._instance._evhs self._callbacks = self._instance._callbacks self._references = self._instance._references @@ -247,11 +258,16 @@ def _getSelfToPersist(self): mapping = self.new(OverlayElementMapping, nchildren=len(self._instmap)) - for key,val in self._instmap.iteritems(): + for key, val in self._instmap.iteritems(): mapping.addChild(self.new(OverlayMap, origin=key, destination=val)) - return self.new(OverlayModel, instance_uuid=self.uuid, topersist=True, model=self.getOverlayModel(), shadow=self._instance, mapping=mapping) + return self.new(OverlayModel, + instance_uuid=self.uuid, + topersist=True, + model=self.getOverlayModel(), + shadow=self._instance, + mapping=mapping) def _clone(self): return self.new(Overlay, model=self.getOverlayModel()) @@ -262,6 +278,9 @@ def _getOverlayModel(self): return self._overlaymodel + def _getOverlayInstance(self): + return self._instance + def _pushChanges(self): for watcher in list(self._watchers.values()): watcher.pushChanges() @@ -280,7 +299,10 @@ self._instance.delChild(child) def _getProperty(self, prop): - return self._instance.getProperty(prop) + try: + return self._instance.getProperty(prop) + except KeyError: + return getattr(self._overlaymodel, prop) def _setProperty(self, prop, val): return self._instance.setProperty(prop, val) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/properties.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/properties.py --- metamodel-0.1.1/metamodel/properties.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/properties.py 2009-12-09 13:50:29.000000000 +0000 @@ -12,50 +12,54 @@ """ Descriptor for model properties (to be included in the class declaration). """ - def __init__(self,proptype,default=None,ro=False,**kwargs): + def __init__(self, proptype, default=None, **kwargs): self._proptype = proptype - self._default = default - self._ro = ro self._metadata = kwargs - if issubclass(proptype,basemodel.SubscribableModel): - self._reference = True - self._prevval = None + self._metadata["default"] = default + self._metadata["type"] = proptype + if issubclass(proptype, basemodel.SubscribableModel): + self._reference = True + self._prevval = None else: - self._reference = False + self._reference = False # self.name = None # XXX has to be set externally !! def __getattr__(self, name): try: - return self._metadata[name] + return self._metadata[name] except: - return None + return None - def __set__(self,obj,val): - if self._reference and not isinstance(val,str): - prevval = None - if len(obj._references[self.name]): - prevval = obj._references[self.name][0] - if val: - # unref and unsubscribe previous - if prevval: - obj._references[self.name].remove(prevval) - prevval._referencedby[self.name].remove(obj) - obj._references[self.name].append(val) - val._referencedby[self.name].append(obj) - elif prevval: - if self.persistent: - return # keep it! - obj._references[self.name].remove(prevval) - prevval._referencedby[self.name].remove(obj) - obj.setProperty(self.name,val) + def __set__(self, obj, val): + if self._reference and not isinstance(val, str): + prevval = None + if len(obj._references[self.name]): + prevval = obj._references[self.name][0] + if val: + # unref and unsubscribe previous + if prevval: + obj._references[self.name].remove(prevval) + prevval._referencedby[self.name].remove(obj) + obj._references[self.name].append(val) + val._referencedby[self.name].append(obj) + elif prevval: + if self.persistent: + return # keep it! + obj._references[self.name].remove(prevval) + prevval._referencedby[self.name].remove(obj) + obj.setProperty(self.name, val) def invalidate(self): pass - def __get__(self,obj,objtype=None): + + def __get__(self, obj, objtype=None): if not obj: # class access return self else: # instance access - return obj.getProperty(self.name) + try: + return obj.getProperty(self.name) + except: + return self.default class Color(Property): @@ -83,6 +87,10 @@ Property.__init__(self, proptype, default, **kwargs) self._options = options +class PropertyFrom(Property): + def __init__(self, default="", **kwargs): + Property.__init__(self, str, default, **kwargs) + class Link(Property): def __init__(self, *args, **kwargs): Property.__init__(self, str, *args, **kwargs) @@ -91,6 +99,10 @@ def __init__(self, *args, **kwargs): Property.__init__(self, float, *args, **kwargs) +class DateTime(Property): + def __init__(self, *args, **kwargs): + Property.__init__(self, float, *args, **kwargs) + class Password(Property): def __init__(self, default="", **kwargs): Property.__init__(self, str, default, **kwargs) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/metamodel/yamlserializer.py /tmp/dmMTQQlFD1/metamodel-0.1.2/metamodel/yamlserializer.py --- metamodel-0.1.1/metamodel/yamlserializer.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/metamodel/yamlserializer.py 2009-12-09 13:50:28.000000000 +0000 @@ -5,7 +5,7 @@ import yaml import dictserializer -from .filters import Filter +from filters import Filter def LoadValue(yamldata): return yaml.load(yamldata) @@ -15,7 +15,10 @@ def LoadModel(yamldata, reqclsname=None, datasource=None): objs = yaml.load(yamldata) - return dictserializer.LoadModel(objs, reqclsname, datasource) + if objs: + return dictserializer.LoadModel(objs, reqclsname, datasource) + else: + return [] def SaveModel(model, data="", objs=None, datasource=None, userfunc=None, greedy=False, class_mapping={}, inst_mapping={}): # save children diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/setup.py /tmp/dmMTQQlFD1/metamodel-0.1.2/setup.py --- metamodel-0.1.1/setup.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/setup.py 2009-12-09 13:53:10.000000000 +0000 @@ -2,7 +2,7 @@ setup( name = "metamodel", - version = "0.1", + version = "0.1.2", packages = find_packages(), ) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/classregistry.py /tmp/dmMTQQlFD1/metamodel-0.1.2/test/classregistry.py --- metamodel-0.1.1/test/classregistry.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/test/classregistry.py 2009-12-09 13:50:28.000000000 +0000 @@ -80,7 +80,7 @@ assert(prop.default == 1.4) # check the old property name dissapeared -assert(hasattr(todotask,"test1"),False) +assert(hasattr(todotask,"test1") == False) # check default remains default assert(todotask.test3 == prop.default) diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/hierarchical.py /tmp/dmMTQQlFD1/metamodel-0.1.2/test/hierarchical.py --- metamodel-0.1.1/test/hierarchical.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/test/hierarchical.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,121 @@ +from metamodel import SubscribableModel as Model + +from metamodel.hierarview import HierarView as View +from metamodel.hierarview import TopHierarView as TopView +class NoView(object): + def __init__(*args): + pass +# models +class A(Model): + pass +class B(Model): + pass +class C(Model): + pass +class D(Model): + pass +class E(Model): + pass +class F(Model): + pass +class G(Model): + pass + +# views +class viewG(View): + pass +class viewF(View): + _model2view = {'G': [viewG]} + +class viewE(View): + pass + +class viewD(NoView): + pass + +class viewC(NoView): + pass + +class viewB(View): + _model2view = {'E': [viewE], + 'F': [viewF]} + +class viewA(TopView): + _model2view = {'B': [viewB]} + + +# --------------- +# a1 [viewA] +# b1 [viewB] +# c1 +# d1 +# e1 [viewE] +# g1 +# c2 +# f1 [viewF] +# g2 {viewG} + +a1 = A() +b1 = B() +c1 = C() +c2 = C() +d1 = D() +e1 = E() +f1 = F() +g1 = F() +g2 = G() + +a1.addChild(b1) +b1.addChild(c1) +b1.addChild(c2) + +c1.addChild(d1) + +d1.addChild(e1) +c2.addChild(f1) + +e1.addChild(g1) +f1.addChild(g2) + +ViewA = viewA(a1) + +# initial view testing +a_children = ViewA._children_views +assert(len(a_children.values()) == 1) +assert(a_children.values()[0].__class__ == viewB) +b_children = a_children.values()[0]._children_views +b_childclasses = map(lambda s: s.__class__, b_children.values()) +assert(len(b_children.values()) == 2) +assert(set(b_childclasses) == set([viewE, viewF])) +f_child = filter(lambda s: s.__class__ == viewF, b_children.values())[0] +assert(len(f_child._children_views.values()) == 1) +assert(f_child._children_views.values()[0].__class__ == viewG) +#ViewA._children_views.values()[0]._children_views +#for bla in ViewA._children_views.values()[0]._children_views.values(): + # print bla._children_views + +# removing nodes +f1.delChild(g2) +assert(len(f_child._children_views.values()) == 0) + +try: + ViewA.getViewNode(f1) + raise Exception,"Didnt get deleted!" +except: + # its ok! + pass + +assert(len(b_children.values()) == 2) +c2.delChild(f1) +assert(len(b_children.values()) == 1) + +# adding nodes +f2 = F() +c2.addChild(f2) +assert(len(b_children.values()) == 2) +c2.addChild(f1) +assert(len(b_children.values()) == 3) + +# test finding child nodes +assert(ViewA.getViewNode(b1) == a_children.values()[0]) + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/ns1.py /tmp/dmMTQQlFD1/metamodel-0.1.2/test/ns1.py --- metamodel-0.1.1/test/ns1.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/test/ns1.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,7 @@ +from metamodel import SubscribableModel as Model + +class AModel(Model): + def test1(self): + pass # just to test its the right class + + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/ns2.py /tmp/dmMTQQlFD1/metamodel-0.1.2/test/ns2.py --- metamodel-0.1.1/test/ns2.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/test/ns2.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,7 @@ +from metamodel import SubscribableModel as Model + +class AModel(Model): + def test2(self): + pass # just to test its the right class + + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/references.py /tmp/dmMTQQlFD1/metamodel-0.1.2/test/references.py --- metamodel-0.1.1/test/references.py 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/test/references.py 2009-12-09 13:50:28.000000000 +0000 @@ -13,7 +13,7 @@ ref4 = Property(TestModel) class TestModel3(SubscribableModel): - ref5 = Property(TestModel,TEST) + ref5 = Property(TestModel) # create some test objects a = TestModel() @@ -21,6 +21,7 @@ c = TestModel2() d = TestModel2() e = TestModel3() +e.ref5 = TEST assert(e.ref5 == TEST) assert(e.getAllReferences() == [TEST]) # assign references diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/testfind.py /tmp/dmMTQQlFD1/metamodel-0.1.2/test/testfind.py --- metamodel-0.1.1/test/testfind.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/test/testfind.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,47 @@ +from metamodel import SubscribableModel, Property + +# model for this test +class NamedModel(SubscribableModel): + name = Property(str) + reference = Property(SubscribableModel) + +# setup a simple graph +a = NamedModel(name="a") +a.addChild(NamedModel(name="b")) +a.addChild(NamedModel(name="c")) +a.getChildren()[1].addChild(NamedModel(name="d")) +a.getChildren()[1].addChild(NamedModel(name="b")) +a.getChildren()[1].getChildren()[1].addChild(NamedModel(name="e")) +a.getChildren()[1].getChildren()[1].reference = NamedModel(name="ref") + +# introduce circular references +a.getChildren()[1].getChildren()[1].addChild(a) +a.getChildren()[1].getChildren()[0].reference = a + +# helper funcions +def printnames(aList): + for obj in aList: + print " *",obj.name, str(obj.uuid) + +def assert_len(result, req_len): + try: + assert(len(result) == req_len) + except: + print "Wrong legth",result + raise Exception + +# Find b +assert_len(a.findChildren(name="b",recursive=True), 2) +# Find d +assert_len(a.findChildren(name="d",recursive=True), 1) +# Find e +assert_len(a.findChildren(name="e",recursive=True), 1) +# Find ref +assert_len(a.findChildren(name="ref",recursive=True), 1) +# Find ref Non recursive +assert_len(a.findChildren(name="ref"), 0) +# Find b Non recursive +assert_len(a.findChildren(name="b"), 1) +# Find d Non recursive +assert_len(a.findChildren(name="d"), 0) + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/testns.py /tmp/dmMTQQlFD1/metamodel-0.1.2/test/testns.py --- metamodel-0.1.1/test/testns.py 1970-01-01 01:00:00.000000000 +0100 +++ metamodel-0.1.2/test/testns.py 2009-12-09 13:50:28.000000000 +0000 @@ -0,0 +1,27 @@ +import ns1 +import ns2 + +from metamodel.meta import ClassRegistry + + +assert(ClassRegistry["ns1.AModel"] == ns1.AModel) +assert(ClassRegistry["ns2.AModel"] == ns2.AModel) + +from metamodel.metamodel import Namespace, MetaModel, MetaProperty +from metamodel.dynamicmeta import Registry + +ns = Namespace(name="foo") +ns2 = Namespace(name="foo2") +cls = MetaModel(name="foo",classname="foo") +cls2 = MetaModel(name="foo3",classname="foo3") + +ns.addChild(cls) +ns.addChild(ns2) +ns2.addChild(cls2) +Registry.addChild(ns) + +assert(ClassRegistry["foo.foo"]) +assert(ClassRegistry["foo.foo2.foo3"]) + +# XXX test some kind of mutant cyclic namespace? + diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/todoontology2.caf /tmp/dmMTQQlFD1/metamodel-0.1.2/test/todoontology2.caf --- metamodel-0.1.1/test/todoontology2.caf 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/test/todoontology2.caf 2009-12-09 13:50:28.000000000 +0000 @@ -45,10 +45,10 @@ classname: TodoThoughtModel inheritfrom: [] name: Thought -Ontology#d15f5d58-c5c4-11dd-8f99-0013e8df9835: +Namespace#d15f5d58-c5c4-11dd-8f99-0013e8df9835: children: [d2d9da3c-c5c4-11dd-8f99-0013e8df9835, d425c7c0-c5c4-11dd-8f99-0013e8df9835, d425c7c1-c5c4-11dd-8f99-0013e8df9835, 0ba5a7ba-c5c5-11dd-8f99-0013e8df9835] - name: Todo Ontology + name: Todo Namespace DataSourceRoot#9a2a8fcc-c607-11dd-8f99-0013e8df9835: children: [d15f5d58-c5c4-11dd-8f99-0013e8df9835] name: Root diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test/todoontology.caf /tmp/dmMTQQlFD1/metamodel-0.1.2/test/todoontology.caf --- metamodel-0.1.1/test/todoontology.caf 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/test/todoontology.caf 2009-12-09 13:50:28.000000000 +0000 @@ -64,10 +64,10 @@ classname: TodoThoughtModel inheritfrom: [] name: Thought -Ontology#d15f5d58-c5c4-11dd-8f99-0013e8df9835: +Namespace#d15f5d58-c5c4-11dd-8f99-0013e8df9835: children: [d2d9da3c-c5c4-11dd-8f99-0013e8df9835, d425c7c0-c5c4-11dd-8f99-0013e8df9835, d425c7c1-c5c4-11dd-8f99-0013e8df9835, 0ba5a7ba-c5c5-11dd-8f99-0013e8df9835] - name: Todo Ontology + name: Todo Namespace DataSourceRoot#9a2a8fcc-c607-11dd-8f99-0013e8df9835: children: [d15f5d58-c5c4-11dd-8f99-0013e8df9835] name: Root diff -Nru /tmp/Fj6aiL8Cc0/metamodel-0.1.1/test.sh /tmp/dmMTQQlFD1/metamodel-0.1.2/test.sh --- metamodel-0.1.1/test.sh 2009-02-27 15:03:43.000000000 +0000 +++ metamodel-0.1.2/test.sh 2009-12-09 13:50:28.000000000 +0000 @@ -1,5 +1,10 @@ export PYTHONPATH=$PWD #TIMEIT=/usr/bin/time + +echo "** Namespaces test" +$TIMEIT python test/testns.py +echo "** Hierarchical view system **" +$TIMEIT python test/hierarchical.py echo "** SubscribableModel tests **" $TIMEIT python test/simpletest.py echo "** Dynamicmeta tests **" @@ -14,3 +19,5 @@ $TIMEIT python test/overlaytest.py echo "** Animation **" $TIMEIT python test/animationtest.py +echo "** Finding functions **" +$TIMEIT python test/testfind.py