| Index: third_party/twisted_8_1/twisted/web/woven/model.py
|
| diff --git a/third_party/twisted_8_1/twisted/web/woven/model.py b/third_party/twisted_8_1/twisted/web/woven/model.py
|
| deleted file mode 100644
|
| index 90153c20cbd9c7ef7e7219cfcf25dbb8f4be9541..0000000000000000000000000000000000000000
|
| --- a/third_party/twisted_8_1/twisted/web/woven/model.py
|
| +++ /dev/null
|
| @@ -1,487 +0,0 @@
|
| -# -*- test-case-name: twisted.web.test.test_woven -*-
|
| -# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
|
| -# See LICENSE for details.
|
| -
|
| -
|
| -__version__ = "$Revision: 1.53 $"[11:-2]
|
| -
|
| -import types
|
| -import weakref
|
| -import warnings
|
| -
|
| -from zope.interface import implements
|
| -
|
| -from twisted.python import components, reflect
|
| -from twisted.internet import defer
|
| -
|
| -from twisted.web.woven import interfaces
|
| -
|
| -class _Nothing: pass
|
| -
|
| -def adaptToIModel(m, parent=None, submodel=None):
|
| - adapted = interfaces.IModel(m, None)
|
| - if adapted is None:
|
| - adapted = Wrapper(m)
|
| - adapted.parent = parent
|
| - adapted.name = submodel
|
| - return adapted
|
| -
|
| -
|
| -class Model:
|
| - """
|
| - A Model which keeps track of views which are looking at it in order
|
| - to notify them when the model changes.
|
| - """
|
| - implements(interfaces.IModel)
|
| -
|
| - def __init__(self, *args, **kwargs):
|
| - if len(args):
|
| - self.original = args[0]
|
| - else:
|
| - self.original = self
|
| - self.name = ''
|
| - self.parent = None
|
| - self.views = []
|
| - self.subviews = {}
|
| - self.submodels = {}
|
| - self._getter = kwargs.get('getter')
|
| - self._setter = kwargs.get('setter')
|
| - self.cachedFor = None
|
| - self.initialize(*args, **kwargs)
|
| -
|
| - def __getstate__(self):
|
| - self.views = []
|
| - self.subviews = {}
|
| - self.submodels = {}
|
| - return self.__dict__
|
| -
|
| - def invalidateCache(self):
|
| - """Invalidate the cache for this object, so the next time
|
| - getData is called, it's getter method is called again.
|
| - """
|
| - self.cachedFor = None
|
| -
|
| - def initialize(self, *args, **kwargs):
|
| - """
|
| - Hook for subclasses to initialize themselves without having to
|
| - mess with the __init__ chain.
|
| - """
|
| - pass
|
| -
|
| - def addView(self, view):
|
| - """
|
| - Add a view for the model to keep track of.
|
| - """
|
| - if view not in [ref() for ref in self.views]:
|
| - self.views.append(weakref.ref(view))
|
| -
|
| - def addSubview(self, name, subview):
|
| - subviewList = self.subviews.get(name, [])
|
| - subviewList.append(weakref.ref(subview))
|
| - self.subviews[name] = subviewList
|
| -
|
| - def removeView(self, view):
|
| - """
|
| - Remove a view that the model no longer should keep track of.
|
| - """
|
| - # AM: loop on a _copy_ of the list, since we're changing it!!!
|
| - for weakref in list(self.views):
|
| - ref = weakref()
|
| - if ref is view or ref is None:
|
| - self.views.remove(weakref)
|
| -
|
| - def setGetter(self, getter):
|
| - self._getter = getter
|
| -
|
| - def setSetter(self, setter):
|
| - self._setter = setter
|
| -
|
| - def notify(self, changed=None):
|
| - """
|
| - Notify all views that something was changed on me.
|
| - Passing a dictionary of {'attribute': 'new value'} in changed
|
| - will pass this dictionary to the view for increased performance.
|
| - If you don't want to do this, don't, and just use the traditional
|
| - MVC paradigm of querying the model for things you're interested
|
| - in.
|
| - """
|
| - self.cachedFor = None
|
| - if changed is None: changed = {}
|
| - retVal = []
|
| - # AM: loop on a _copy_ of the list, since we're changing it!!!
|
| - for view in list(self.views):
|
| - ref = view()
|
| - if ref is not None:
|
| - retVal.append((ref, ref.modelChanged(changed)))
|
| - else:
|
| - self.views.remove(view)
|
| - for key, value in self.subviews.items():
|
| - if value.wantsAllNotifications or changed.has_key(key):
|
| - for item in list(value):
|
| - ref = item()
|
| - if ref is not None:
|
| - retVal.append((ref, ref.modelChanged(changed)))
|
| - else:
|
| - value.remove(item)
|
| - return retVal
|
| -
|
| - protected_names = ['initialize', 'addView', 'addSubview', 'removeView', 'notify', 'getSubmodel', 'setSubmodel', 'getData', 'setData']
|
| - allowed_names = []
|
| -
|
| - def lookupSubmodel(self, request, submodelName):
|
| - """
|
| - Look up a full submodel name. I will split on `/' and call
|
| - L{getSubmodel} on each element in the 'path'.
|
| -
|
| - Override me if you don't want 'traversing'-style lookup, but
|
| - would rather like to look up a model based on the entire model
|
| - name specified.
|
| -
|
| - If you override me to return Deferreds, make sure I look up
|
| - values in a cache (created by L{setSubmodel}) before doing a
|
| - regular Deferred lookup.
|
| -
|
| - XXX: Move bits of this docstring to interfaces.py
|
| - """
|
| - if not submodelName:
|
| - return None
|
| -
|
| - # Special case: If the first character is /
|
| - # Start at the bottom of the model stack
|
| - currentModel = self
|
| - if submodelName[0] == '/':
|
| - while currentModel.parent is not None:
|
| - currentModel = currentModel.parent
|
| - submodelName = submodelName[1:]
|
| -
|
| - submodelList = submodelName.split('/') #[:-1]
|
| -# print "submodelList", submodelList
|
| - for element in submodelList:
|
| - if element == '.' or element == '':
|
| - continue
|
| - elif element == '..':
|
| - currentModel = currentModel.parent
|
| - else:
|
| - currentModel = currentModel.getSubmodel(request, element)
|
| - if currentModel is None:
|
| - return None
|
| - return currentModel
|
| -
|
| - def submodelCheck(self, request, name):
|
| - """Check if a submodel name is allowed. Subclass me to implement a
|
| - name security policy.
|
| - """
|
| - if self.allowed_names:
|
| - return (name in self.allowed_names)
|
| - else:
|
| - return (name and name[0] != '_' and name not in self.protected_names)
|
| -
|
| -
|
| - def submodelFactory(self, request, name):
|
| - warnings.warn("Warning: default Model lookup strategy is changing:"
|
| - "use either AttributeModel or MethodModel for now.",
|
| - DeprecationWarning)
|
| - if hasattr(self, name):
|
| - return getattr(self, name)
|
| - else:
|
| - return None
|
| -
|
| - def getSubmodel(self, request, name):
|
| - """
|
| - Get the submodel `name' of this model. If I ever return a
|
| - Deferred, then I ought to check for cached values (created by
|
| - L{setSubmodel}) before doing a regular Deferred lookup.
|
| - """
|
| - if self.submodels.has_key(name):
|
| - return self.submodels[name]
|
| - if not self.submodelCheck(request, name):
|
| - return None
|
| - m = self.submodelFactory(request, name)
|
| - if m is None:
|
| - return None
|
| - sm = adaptToIModel(m, self, name)
|
| - self.submodels[name] = sm
|
| - return sm
|
| -
|
| - def setSubmodel(self, request=None, name=None, value=None):
|
| - """
|
| - Set a submodel on this model. If getSubmodel or lookupSubmodel
|
| - ever return a Deferred, I ought to set this in a place that
|
| - lookupSubmodel/getSubmodel know about, so they can use it as a
|
| - cache.
|
| - """
|
| - if self.submodelCheck(request, name):
|
| - if self.submodels.has_key(name):
|
| - del self.submodels[name]
|
| - setattr(self, name, value)
|
| -
|
| - def dataWillChange(self):
|
| - pass
|
| -
|
| - def getData(self, request):
|
| - if self.cachedFor != id(request) and self._getter is not None:
|
| - self.cachedFor = id(request)
|
| - self.dataWillChange()
|
| - self.orig = self.original = self._getter(request)
|
| - return self.original
|
| -
|
| - def setData(self, request, data):
|
| - if self._setter is not None:
|
| - self.cachedFor = None
|
| - return self._setter(request, data)
|
| - else:
|
| - if hasattr(self, 'parent') and self.parent:
|
| - self.parent.setSubmodel(request, self.name, data)
|
| - self.orig = self.original = data
|
| -
|
| -
|
| -class MethodModel(Model):
|
| - """Look up submodels with wmfactory_* methods.
|
| - """
|
| -
|
| - def submodelCheck(self, request, name):
|
| - """Allow any submodel for which I have a submodel.
|
| - """
|
| - return hasattr(self, "wmfactory_"+name)
|
| -
|
| - def submodelFactory(self, request, name):
|
| - """Call a wmfactory_name method on this model.
|
| - """
|
| - meth = getattr(self, "wmfactory_"+name)
|
| - return meth(request)
|
| -
|
| - def getSubmodel(self, request=None, name=None):
|
| - if name is None:
|
| - warnings.warn("Warning! getSubmodel should now take the request as the first argument")
|
| - name = request
|
| - request = None
|
| -
|
| - cached = self.submodels.has_key(name)
|
| - sm = Model.getSubmodel(self, request, name)
|
| - if sm is not None:
|
| - if not cached:
|
| - sm.cachedFor = id(request)
|
| - sm._getter = getattr(self, "wmfactory_"+name)
|
| - return sm
|
| -
|
| -
|
| -class AttributeModel(Model):
|
| - """Look up submodels as attributes with hosts.allow/deny-style security.
|
| - """
|
| - def submodelFactory(self, request, name):
|
| - if hasattr(self, name):
|
| - return getattr(self, name)
|
| - else:
|
| - return None
|
| -
|
| -
|
| -#backwards compatibility
|
| -WModel = Model
|
| -
|
| -
|
| -class Wrapper(Model):
|
| - """
|
| - I'm a generic wrapper to provide limited interaction with the
|
| - Woven models and submodels.
|
| - """
|
| - parent = None
|
| - name = None
|
| - def __init__(self, orig):
|
| - Model.__init__(self)
|
| - self.orig = self.original = orig
|
| -
|
| - def dataWillChange(self):
|
| - pass
|
| -
|
| - def __repr__(self):
|
| - myLongName = reflect.qual(self.__class__)
|
| - return "<%s instance at 0x%x: wrapped data: %s>" % (myLongName,
|
| - id(self), self.original)
|
| -
|
| -
|
| -class ListModel(Wrapper):
|
| - """
|
| - I wrap a Python list and allow it to interact with the Woven
|
| - models and submodels.
|
| - """
|
| - def dataWillChange(self):
|
| - self.submodels = {}
|
| -
|
| - def getSubmodel(self, request=None, name=None):
|
| - if name is None and type(request) is type(""):
|
| - warnings.warn("Warning!")
|
| - name = request
|
| - request = None
|
| - if self.submodels.has_key(name):
|
| - return self.submodels[name]
|
| - orig = self.original
|
| - try:
|
| - i = int(name)
|
| - except:
|
| - return None
|
| - if i > len(orig):
|
| - return None
|
| - sm = adaptToIModel(orig[i], self, name)
|
| - self.submodels[name] = sm
|
| - return sm
|
| -
|
| - def setSubmodel(self, request=None, name=None, value=None):
|
| - if value is None:
|
| - warnings.warn("Warning!")
|
| - value = name
|
| - name = request
|
| - request = None
|
| - self.original[int(name)] = value
|
| -
|
| - def __len__(self):
|
| - return len(self.original)
|
| -
|
| - def __getitem__(self, name):
|
| - return self.getSubmodel(None, str(name))
|
| -
|
| - def __setitem__(self, name, value):
|
| - self.setSubmodel(None, str(name), value)
|
| -
|
| - def __repr__(self):
|
| - myLongName = reflect.qual(self.__class__)
|
| - return "<%s instance at 0x%x: wrapped data: %s>" % (myLongName,
|
| - id(self), self.original)
|
| -
|
| -
|
| -class StringModel(ListModel):
|
| -
|
| - """ I wrap a Python string and allow it to interact with the Woven models
|
| - and submodels. """
|
| -
|
| - def setSubmodel(self, request=None, name=None, value=None):
|
| - raise ValueError("Strings are immutable.")
|
| -
|
| -
|
| -# pyPgSQL returns "PgResultSet" instances instead of lists, which look, act
|
| -# and breathe just like lists. pyPgSQL really shouldn't do this, but this works
|
| -try:
|
| - from pyPgSQL import PgSQL
|
| - components.registerAdapter(ListModel, PgSQL.PgResultSet, interfaces.IModel)
|
| -except:
|
| - pass
|
| -
|
| -class DictionaryModel(Wrapper):
|
| - """
|
| - I wrap a Python dictionary and allow it to interact with the Woven
|
| - models and submodels.
|
| - """
|
| - def dataWillChange(self):
|
| - self.submodels = {}
|
| -
|
| - def getSubmodel(self, request=None, name=None):
|
| - if name is None and type(request) is type(""):
|
| - warnings.warn("getSubmodel must get a request argument now")
|
| - name = request
|
| - request = None
|
| - if self.submodels.has_key(name):
|
| - return self.submodels[name]
|
| - orig = self.original
|
| - if name not in orig:
|
| - return None
|
| - sm = adaptToIModel(orig[name], self, name)
|
| - self.submodels[name] = sm
|
| - return sm
|
| -
|
| - def setSubmodel(self, request=None, name=None, value=None):
|
| - if value is None:
|
| - warnings.warn("Warning!")
|
| - value = name
|
| - name = request
|
| - request = None
|
| - self.original[name] = value
|
| -
|
| -
|
| -class AttributeWrapper(Wrapper):
|
| - """
|
| - I wrap an attribute named "name" of the given parent object.
|
| - """
|
| - def __init__(self, parent, name):
|
| - self.original = None
|
| - parent = ObjectWrapper(parent)
|
| - Wrapper.__init__(self, parent.getSubmodel(None, name))
|
| - self.parent = parent
|
| - self.name = name
|
| -
|
| -
|
| -class ObjectWrapper(Wrapper):
|
| - """
|
| - I may wrap an object and allow it to interact with the Woven models
|
| - and submodels. By default, I am not registered for use with anything.
|
| - """
|
| - def getSubmodel(self, request=None, name=None):
|
| - if name is None and type(request) is type(""):
|
| - warnings.warn("Warning!")
|
| - name = request
|
| - request = None
|
| - if self.submodels.has_key(name):
|
| - return self.submodels[name]
|
| - sm = adaptToIModel(getattr(self.original, name), self, name)
|
| - self.submodels[name] = sm
|
| - return sm
|
| -
|
| - def setSubmodel(self, request=None, name=None, value=None):
|
| - if value is None:
|
| - warnings.warn("Warning!")
|
| - value = name
|
| - name = request
|
| - request = None
|
| - setattr(self.original, name, value)
|
| -
|
| -class UnsafeObjectWrapper(ObjectWrapper):
|
| - """
|
| - I may wrap an object and allow it to interact with the Woven models
|
| - and submodels. By default, I am not registered for use with anything.
|
| - I am unsafe because I allow methods to be called. In fact, I am
|
| - dangerously unsafe. Be wary or I will kill your security model!
|
| - """
|
| - def getSubmodel(self, request=None, name=None):
|
| - if name is None and type(request) is type(""):
|
| - warnings.warn("Warning!")
|
| - name = request
|
| - request = None
|
| - if self.submodels.has_key(name):
|
| - return self.submodels[name]
|
| - value = getattr(self.original, name)
|
| - if callable(value):
|
| - return value()
|
| - sm = adaptToIModel(value, self, name)
|
| - self.submodels = sm
|
| - return sm
|
| -
|
| -
|
| -class DeferredWrapper(Wrapper):
|
| - def setData(self, request=None, data=_Nothing):
|
| - if data is _Nothing:
|
| - warnings.warn("setData should be called with request as first arg")
|
| - data = request
|
| - request = None
|
| - if isinstance(data, defer.Deferred):
|
| - self.original = data
|
| - else:
|
| - views, subviews = self.views, self.subviews
|
| - new = adaptToIModel(data, self.parent, self.name)
|
| - self.__class__ = new.__class__
|
| - self.__dict__ = new.__dict__
|
| - self.views, self.subviews = views, subviews
|
| -
|
| -class Link(AttributeModel):
|
| - def __init__(self, href, text):
|
| - AttributeModel.__init__(self)
|
| - self.href = href
|
| - self.text = text
|
| -
|
| -try:
|
| - components.registerAdapter(StringModel, types.StringType, interfaces.IModel)
|
| - components.registerAdapter(ListModel, types.ListType, interfaces.IModel)
|
| - components.registerAdapter(ListModel, types.TupleType, interfaces.IModel)
|
| - components.registerAdapter(DictionaryModel, types.DictionaryType, interfaces.IModel)
|
| - components.registerAdapter(DeferredWrapper, defer.Deferred, interfaces.IModel)
|
| - components.registerAdapter(DeferredWrapper, defer.DeferredList, interfaces.IModel)
|
| -except ValueError:
|
| - # The adapters were already registered
|
| - pass
|
|
|