# Copyright (c) 2004 Divmod.
# See LICENSE for details.
from zope.interface import implements,providedBy
from formless.iformless import IConfigurable,IActionableType,IBinding
from formless.annotate import Argument,ElementBinding,GroupBinding,Object,TypedInterface
from nevow import inevow
from nevow.context import WovenContext
class Configurable(object):
implements(IConfigurable)
bindingDict = None
def __init__(self, original):
self.original = original
self.boundTo = self
def getBindingNames(self, context):
## Todo: remove this getattr
ifs = providedBy(getattr(self, 'boundTo', self))
ifs = [
x for x in ifs if x is not IConfigurable and x is not TypedInterface
]
bindingNames = []
self.bindingDict = bindingDict = {}
for interface in ifs:
## TypedInterfaces have a __spec__ attribute which is a list of all Typed properties and
## autocallable methods
for binding in getattr(interface, '__spec__', []):
bindingDict[binding.name] = binding
if binding.name not in bindingNames:
bindingNames.append(binding.name)
if IActionableType.providedBy(binding.typedValue):
acts = binding.typedValue.actions
if acts is None:
acts = []
for action in acts:
bindingDict[action.name] = action
return bindingNames
def getDefault(self, forBinding):
## TODO: Clean this up, it's a mess
if not isinstance(forBinding, Argument):
name = forBinding.name
if hasattr(self, name):
return getattr(self, name)
## Todo: Only do this in ConfigurableAdapter instead of Configurable
if hasattr(self.boundTo, name):
return getattr(self.boundTo, name)
if self.original is not self.boundTo and hasattr(self.original, name):
return getattr(self.original, name)
return forBinding.default
def getBinding(self, context, name):
if self.bindingDict is None:
self.getBindingNames(context)
if self.bindingDict is None:
self.bindingDict = {}
binding = getattr(self, 'bind_%s' % name, getattr(self.boundTo, 'bind_%s' % name, None))
if binding is not None:
binding = binding(context)
else:
try:
binding = self.bindingDict[name]
except KeyError:
raise RuntimeError, "%s is not an exposed binding on object %s." % (name, self.boundTo)
binding.boundTo = self.boundTo
return binding
def postForm(self, ctx, bindingName, args):
"""Accept a form post to the given bindingName. The bindingName
can be dotted to indicate an attribute of this Configurable, eg
addresses.0.changeEmail. The post arguments are given in args.
Return a Resource which will be rendered in response.
"""
from formless import iformless
from nevow.tags import invisible
request = ctx.locate(inevow.IRequest)
pathSegs = bindingName.split('.')
configurable = self
cf = ctx.locate(iformless.IConfigurableFactory)
## Get the first binding
firstSeg = pathSegs.pop(0)
binding = configurable.getBinding(ctx, firstSeg)
ctx.remember(binding, IBinding)
ctx.remember(configurable, IConfigurable)
## I don't think this works right now, it needs to be fixed.
## Most cases it won't be triggered, because we're just traversing a
## single binding name
for seg in pathSegs:
assert 1 == 0, "Sorry, this doesn't work right now"
binding = configurable.getBinding(ctx, seg)
child = self.boundTo
if not isinstance(binding, GroupBinding):
accessor = inevow.IContainer(configurable.boundTo, None)
if accessor is None:
child = getattr(configurable.boundTo, binding.name)
else:
child = accessor.child(ctx, binding.name)
## If it's a groupbinding, we don't do anything at all for this path segment
## This won't work right now. We need to push the previous configurable
## as the configurableFactory somehow and ask that for hte next binding
## we also need to support deferreds coming back from locateConfigurable
assert 'black' is 'white', "Deferred support is pending"
configurable = cf.locateConfigurable(ctx, child)
ctx = WovenContext(ctx, invisible(key=seg))
ctx.remember(binding, IBinding)
ctx.remember(configurable, IConfigurable)
bindingProcessor = iformless.IInputProcessor(binding)
rv = bindingProcessor.process(ctx, binding.boundTo, args)
ctx.remember(rv, inevow.IHand)
ctx.remember('%r success.' % bindingName, inevow.IStatusMessage)
return rv
def summary(self):
return "An instance of %s" % self.__class__.__name__
postLocation = None
class NotFoundConfigurable(Configurable):
def getBinding(self, context, name):
raise RuntimeError, self.original
class TypedInterfaceConfigurable(Configurable):
def __init__(self, original):
self.original = original
self.boundTo = original
def summary(self):
return "An instance of %s" % self.original.__class__.__name__
def __repr__(self):
return "TypedInterfaceConfigurable(%r)" % self.original
class ListConfigurable(TypedInterfaceConfigurable):
def getBinding(self, context, name):
eb = ElementBinding(name, Object())
eb.boundTo = self.original
return eb
class GroupConfigurable(TypedInterfaceConfigurable):
def __init__(self, original, groupInterface):
TypedInterfaceConfigurable.__init__(self, original)
self.groupInterface = groupInterface
bindingDict = None
def getBindingNames(self, context):
bindingNames = []
self.bindingDict = bindingDict = {}
interface = self.groupInterface
for binding in getattr(interface, '__spec__', []):
bindingDict[binding.name] = binding
if binding.name not in bindingNames:
bindingNames.append(binding.name)
if IActionableType.providedBy(binding.typedValue):
acts = binding.typedValue.actions
if acts is None:
acts = []
for action in acts:
bindingDict[action.name] = action
return bindingNames
|