Source code for tw2.core.params

from __future__ import absolute_import

from . import core
import itertools
import copy
import six


class ParameterError(core.WidgetError):
    "Errors related to parameters."


class _Required(object):
    """This class is used to mark a widget parameter as being required, by
    setting the default value to this."""
    def __repr__(self):
        return 'Required'
Required = _Required()


class _Auto(object):
    """
    Used to explicitly mark a parameter as being automatically generated.
    """
    def __repr__(self):
        return 'Auto'
Auto = _Auto()


[docs]class Deferred(object): """This class is used as a wrapper around a parameter value. It takes a callable, which will be called every time the widget is displayed, with the returned value giving the parameter value.""" def __init__(self, fn): self.fn = fn def __repr__(self): doc = self.fn.__doc__ if self.fn.__doc__ else '<Deferred>' return '<Deferred: %s>' % doc
class _Default(object): def __repr__(self): return 'Default' Default = _Default() _param_seq = itertools.count(0)
[docs]class Param(object): """A parameter for a widget. `description` A string to describe the parameter. When overriding a parameter description, the string can include ``$$`` to insert the previous description. `default` The default value for the parameter. If no defalt is specified, the parameter is a required parameter. This can also be specified explicitly using tw.Required. `request_local` Can the parameter be overriden on a per-request basis? (default: True) `attribute` Should the parameter be automatically included as an attribute? (default: False) `view_name` The name used for the attribute. This is useful for attributes like *class* which are reserved names in Python. If this is None, the name is used. (default: None) The class takes care to record which arguments have been explictly specifed, even if to their default value. If a parameter from a base class is updated in a subclass, arguments that have been explicitly specified will override the base class. """ child_param = False internal = False name = None defined_on = None view_name = None def __init__(self, description=Default, default=Default, request_local=Default, attribute=Default, view_name=Default): self._seq = six.advance_iterator(_param_seq) self.description = None if description is not Default: self.description = description self.default = Required if default is not Default: self.default = default self.request_local = True if request_local is not Default: self.request_local = request_local self.attribute = False if attribute is not Default: self.attribute = attribute self.view_name = None if view_name is not Default: self.view_name = view_name self.specified = [] args = [ 'description', 'default', 'request_local', 'attribute', 'view_name', ] for arg in args: if locals()[arg] is not Default: self.specified.append(arg) def __repr__(self): return '%s: %s (default: %s, defined on: %s)' % ( self.name, self.description, self.default, self.defined_on)
[docs]class Variable(Param): """A variable - a parameter that is passed from the widget to the template, but cannot be controlled by the user. These do not appear in the concise documentation for the widget. """ internal = True def __init__(self, description=Default, **kw): kw.setdefault('default', None) super(Variable, self).__init__(description, **kw) self.specified.append('internal')
[docs]class ChildParam(Param): """A parameter that applies to children of this widget This is useful for situations such as a layout widget, which adds a :attr:`label` parameter to each of its children. When a Widget subclass is defined with a parent, the widget picks up the defaults for any child parameters from the parent. """ child_param = True
[docs]class ChildVariable(Variable, ChildParam): """A variable that applies to children of this widget """ pass
class ParamMeta(type): "Meta class the collects parameters." def __new__(meta, name, bases, dct): """Create a new `Widget` subclass. This detects `Param` instances defined declaratively, updates with information from the containing class, and stores the objects in `_params`.""" params = {} for b in bases: if hasattr(b, '_params'): params.update(b._all_params) for pname, prm in list(dct.items()): if isinstance(prm, Param): if pname in params: newprm = prm prm = copy.copy(params[pname]) for a in newprm.specified: setattr(prm, a, getattr(newprm, a)) else: prm.name = pname if prm.view_name is None: prm.view_name = pname prm.defined_on = name params[pname] = prm if not prm.child_param and prm.default is not Required: dct[pname] = prm.default else: del dct[pname] elif pname in params: params[pname] = copy.copy(params[pname]) params[pname].default = prm if prm is Required and pname != 'validator': del dct[pname] ins = type.__new__(meta, name, bases, dct) ins._all_params = params ins._params = dict((p.name, p) for p in params.values() if not p.child_param) return ins class Parametered(six.with_metaclass(ParamMeta, object)): pass