Ignore:
Timestamp:
Nov 9, 2011, 6:44:36 PM (10 years ago)
Author:
Ralph Meijer <ralphm@…>
Branch:
default
Children:
155:8b2ed9549399, 159:bbb746f79718
Message:

Allow wokkel.data_form.Form to be used as a read-only dict.

In [1334124db2fd] wokkel.pubsub.PubSubRequest.options was changed to be a
Form instead of dictionary, which makes existing code using that field to be
incompatible.

To reduce the impact of that change, this change implements various methods in
wokkel.data_form.Form to emulate a read-only dictionary. It now maps the
name of each field to its value, similar to the dictionary returned from
getValues. The latter is now identical to dict(form).

  • * *

Address incompatible change concerning PubSubRequest?.options.

In changeset [1334124db2fd], PubSubRequest.options was changed to hold the
wokkel.data_form.Form that represents the data form sent in the original
request. This makes it easier to type check the form in a step separate from
parsing the request. However, this is an incompatible change.

To remedy this, we move the form to optionsForm and make options a property
that returns the values of the form.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • wokkel/data_form.py

    r96 r105  
    1313"""
    1414
     15from zope.interface import implements
     16from zope.interface.common import mapping
    1517from twisted.words.protocols.jabber.jid import JID
    1618from twisted.words.xish import domish
     
    4850    @type value: C{unicode}
    4951    @ivar label: Optional label for this option.
    50     @type label: C{unicode} or C{NoneType}.
     52    @type label: C{unicode} or C{NoneType}
    5153    """
    5254
     
    9597    @ivar fieldType: Type of this field. One of C{'boolean'}, C{'fixed'},
    9698                     C{'hidden'}, C{'jid-multi'}, C{'jid-single'},
    97                      C{'list-multi'}, {'list-single'}, C{'text-multi'},
     99                     C{'list-multi'}, C{'list-single'}, C{'text-multi'},
    98100                     C{'text-private'}, C{'text-single'}.
    99101
    100102                     The default is C{'text-single'}.
    101103    @type fieldType: C{str}
    102     @ivar var: Field name. Optional if L{fieldType} is C{'fixed'}.
     104    @ivar var: Field name. Optional if C{fieldType} is C{'fixed'}.
    103105    @type var: C{str}
    104106    @ivar label: Human readable label for this field.
     
    109111    @ivar options: List of possible values to choose from in a response
    110112                   to this form as a list of L{Option}s.
    111     @type options: C{list}.
     113    @type options: C{list}
    112114    @ivar desc: Human readable description for this field.
    113115    @type desc: C{unicode}
    114116    @ivar required: Whether the field is required to be provided in a
    115117                    response to this form.
    116     @type required: C{bool}.
     118    @type required: C{bool}
    117119    """
    118120
     
    366368    is recorded in the C{formNamespace} instance variable.
    367369
     370    A L{Form} also acts as read-only dictionary, with the values of fields
     371    keyed by their name. See L{__getitem__}.
     372
    368373    @ivar formType: Type of form. One of C{'form'}, C{'submit'}, {'cancel'},
    369374                    or {'result'}.
     
    379384    @ivar formNamespace: The optional namespace of the field names for this
    380385        form. This goes in the special field named C{'FORM_TYPE'}, if set.
    381     @type formNamespace: C{str}.
     386    @type formNamespace: C{str}
    382387
    383388    @ivar fields: Dictionary of named fields. Note that this is meant to be
     
    390395    @type fieldList: C{list}
    391396    """
     397
     398    implements(mapping.IIterableMapping,
     399               mapping.IEnumerableMapping,
     400               mapping.IReadMapping,
     401               mapping.IItemMapping)
    392402
    393403    def __init__(self, formType, title=None, instructions=None,
     
    469479        is rendered using L{toElement}, these fields will have no C{'type'}
    470480        attribute, and it is up to the receiving party to interpret the values
    471         properly (e.g. by knowing about the FORM_TYPE in L{formNamespace} and
     481        properly (e.g. by knowing about the FORM_TYPE in C{formNamespace} and
    472482        the field name).
    473483
     
    568578
    569579
     580    def __iter__(self):
     581        return iter(self.fields)
     582
     583
     584    def __len__(self):
     585        return len(self.fields)
     586
     587
     588    def __getitem__(self, key):
     589        """
     590        Called to implement evaluation of self[key].
     591
     592        This returns the value of the field with the name in C{key}. For
     593        multi-value fields, the value is a list, otherwise a single value.
     594
     595        If a field has no type, and the field has multiple values, the value
     596        of the list of values. Otherwise, it will be a single value.
     597
     598        Raises C{KeyError} if there is no field with the name in C{key}.
     599        """
     600        field = self.fields[key]
     601
     602        if (field.fieldType in ('jid-multi', 'list-multi', 'text-multi') or
     603            (field.fieldType is None and len(field.values) > 1)):
     604            value = field.values
     605        else:
     606            value = field.value
     607
     608        return value
     609
     610
     611    def get(self, key, default=None):
     612        try:
     613            return self[key]
     614        except KeyError:
     615            return default
     616
     617
     618    def __contains__(self, key):
     619        return key in self.fields
     620
     621
     622    def iterkeys(self):
     623        return iter(self)
     624
     625
     626    def itervalues(self):
     627        for key in self:
     628            yield self[key]
     629
     630
     631    def iteritems(self):
     632        for key in self:
     633            yield (key, self[key])
     634
     635
     636    def keys(self):
     637        return list(self)
     638
     639
     640    def values(self):
     641        return list(self.itervalues())
     642
     643
     644    def items(self):
     645        return list(self.iteritems())
     646
     647
    570648    def getValues(self):
    571649        """
     
    573651
    574652        For all named fields, the corresponding value or values are
    575         returned in a dictionary keyed by the field name. For multi-value
    576         fields, the dictionary value is a list, otherwise a single value.
    577 
    578         If a field has no type, and the field has multiple values, the value of
    579         the dictionary entry is the list of values. Otherwise, it will be a
    580         single value.
    581 
     653        returned in a dictionary keyed by the field name. This is equivalent
     654        do C{dict(f)}, where C{f} is a L{Form}.
     655
     656        @see: L{__getitem__}
    582657        @rtype: C{dict}
    583658        """
    584         values = {}
    585 
    586         for name, field in self.fields.iteritems():
    587             if (field.fieldType in ('jid-multi', 'list-multi', 'text-multi') or
    588                 (field.fieldType is None and len(field.values) > 1)):
    589                 value = field.values
    590             else:
    591                 value = field.value
    592 
    593             values[name] = value
    594 
    595         return values
     659        return dict(self)
    596660
    597661
Note: See TracChangeset for help on using the changeset viewer.