source:
ralphm-patches/pubsub-forms.patch
@
26:59ace4d1df68
Last change on this file since 26:59ace4d1df68 was 26:59ace4d1df68, checked in by Ralph Meijer <ralphm@…>, 13 years ago | |
---|---|
File size: 17.8 KB |
-
wokkel/data_form.py
Move makeFields to wokkel.data_form, add form type checking. diff -r ba58db23e8b9 wokkel/data_form.py
a b 76 76 option['label'] = self.label 77 77 return option 78 78 79 79 80 @staticmethod 80 81 def fromElement(element): 81 82 valueElements = list(domish.generateElementsQNamed(element.children, … … 212 213 213 214 if self.values: 214 215 if (self.fieldType not in ('hidden', 'jid-multi', 'list-multi', 215 'text-multi') and216 'text-multi') and 216 217 len(self.values) > 1): 217 218 raise TooManyValuesError() 218 219 … … 233 234 234 235 self.values = newValues 235 236 237 236 238 def toElement(self, asForm=False): 237 239 """ 238 240 Return the DOM representation of this Field. … … 322 324 323 325 324 326 @staticmethod 325 def fromDict(dictionary): 326 kwargs = dictionary.copy() 327 def fromDict(fieldDict): 328 """ 329 Create a field from a dictionary. 327 330 328 if 'type' in dictionary: 329 kwargs['fieldType'] = dictionary['type'] 331 This is a short hand for passing arguments directly on Field object 332 creation. The field type is represented by the C{'type'} key. For 333 C{'options'} the value is not a list of L{Option}s, but a dictionary 334 keyed by value, with an optional label as value. 335 """ 336 kwargs = fieldDict.copy() 337 338 if 'type' in fieldDict: 339 kwargs['fieldType'] = fieldDict['type'] 330 340 del kwargs['type'] 331 341 332 if 'options' in dictionary:342 if 'options' in fieldDict: 333 343 options = [] 334 for value, label in dictionary['options'].iteritems():344 for value, label in fieldDict['options'].iteritems(): 335 345 options.append(Option(value, label)) 336 346 kwargs['options'] = options 337 347 … … 415 425 """ 416 426 Add a field to this form. 417 427 418 Fields are added in order, and L{fields} is a dictionary of the428 Fields are added in order, and C{fields} is a dictionary of the 419 429 named fields, that is kept in sync only if this method is used for 420 430 adding new fields. Multiple fields with the same name are disallowed. 421 431 """ … … 428 438 self.fieldList.append(field) 429 439 430 440 441 def removeField(self, field): 442 """ 443 Remove a field from this form. 444 """ 445 self.fieldList.remove(field) 446 447 if field.var is not None: 448 del self.fields[field.var] 449 450 451 def makeFields(self, values, fieldDefs=None, filterUnknown=True): 452 """ 453 Create fields from values and add them to this form. 454 455 This creates fields from a mapping of name to value(s) and adds them to 456 this form. It is typically used for generating outgoing forms. 457 458 If C{fieldDefs} is not C{None}, this is used to fill in 459 additional properties of fields, like the field types, labels and 460 possible options. 461 462 If C{filterUnknown} is C{True} and C{fieldDefs} is not C{None}, fields 463 will only be created from C{values} with a corresponding entry in 464 C{fieldDefs}. 465 466 If the field type is unknown, the field type is derived from the field 467 value. For single values, if the value is a C{bool}, C{'boolean'} s 468 used, for L{JID} C{'jid-single'}, and C{'text-single'} otherwise. For 469 multiple values, if the first item is a L{JID} C{'jid-multi'} is used. 470 Otherwise C{'list-multi'}. 471 472 Note that the values are used as given, no type coersion or checking 473 is performed. Use L{typeCheck} to check types and coerce values of 474 fields added to a form. 475 476 @param values: Values to create fields from. 477 @type values: C{dict} 478 479 @param fieldDefs: Field definitions as a dictionary. See 480 L{wokkel.iwokkel.IPubSubService.getConfigurationOptions} 481 @type fieldDefs: C{dict} 482 483 @param filterUnknown: If C{True}, ignore fields that are not in 484 C{fieldDefs}. 485 @type filterUnknown: C{bool} 486 """ 487 for name, value in values.iteritems(): 488 fieldDict = {'var': name} 489 490 if fieldDefs is not None: 491 if name in fieldDefs: 492 fieldDict.update(fieldDefs[name]) 493 elif filterUnknown: 494 continue 495 496 if isinstance(value, list): 497 fieldDict['values'] = value 498 if 'type' not in fieldDict: 499 if value and hasattr(value[0], 'full'): 500 fieldDict['type'] = 'jid-multi' 501 else: 502 fieldDict['type'] = 'list-multi' 503 else: 504 fieldDict['value'] = value 505 if 'type' not in fieldDict: 506 if hasattr(value, 'full'): 507 fieldDict['type'] = 'jid-single' 508 elif isinstance(value, bool): 509 fieldDict['type'] = 'boolean' 510 511 self.addField(Field.fromDict(fieldDict)) 512 513 431 514 def toElement(self): 515 """ 516 Return the DOM representation of this Form. 517 518 @rtype: L{domish.Element} 519 """ 432 520 form = domish.Element((NS_X_DATA, 'x')) 433 521 form['type'] = self.formType 434 522 … … 516 604 values[name] = value 517 605 518 606 return values 607 608 609 def typeCheck(self, fieldDefs, filterUnknown=False): 610 """ 611 Check values of fields according to the field definition. 612 613 This method walks all named fields to check their values against their 614 type, and is typically used for forms received from other entities.The 615 field definition in C{fieldDefs} is used to check the field type. 616 617 If C{filterUnknown} is C{True}, fields that are not present in 618 C{fieldDefs} are removed from the form. 619 620 If the field type is C{None} (when not set by the sending entity), 621 the type from the field definitition is used, or C{'text-single'} if 622 that is not set. 623 624 @param fieldDefs: Field definitions as a dictionary. See 625 L{wokkel.iwokkel.IPubSubService.getConfigurationOptions} 626 @type fieldDefs: C{dict} 627 628 @param filterUnknown: If C{True}, remove fields that are not in 629 C{fieldDefs}. 630 @type filterUnknown: C{bool} 631 """ 632 633 filtered = [] 634 635 for name, field in self.fields.iteritems(): 636 if name in fieldDefs: 637 fieldDef = fieldDefs[name] 638 if 'type' not in fieldDef: 639 fieldDef['type'] = 'text-single' 640 641 if field.fieldType is None: 642 field.fieldType = fieldDef['type'] 643 elif field.fieldType != fieldDef['type']: 644 raise TypeError("Field type for %r is %r, expected %r" % 645 (name, 646 field.fieldType, 647 fieldDef['type'])) 648 else: 649 # Field type is correct 650 pass 651 field.typeCheck() 652 elif filterUnknown: 653 filtered.append(field) 654 else: 655 # Unknown field, not filtering 656 pass 657 658 for field in filtered: 659 self.removeField(field) -
wokkel/pubsub.py
diff -r ba58db23e8b9 wokkel/pubsub.py
a b 1 1 # -*- test-case-name: wokkel.test.test_pubsub -*- 2 2 # 3 # Copyright (c) 2003-20 09Ralph Meijer3 # Copyright (c) 2003-2010 Ralph Meijer 4 4 # See LICENSE for details. 5 5 6 6 """ … … 1012 1012 return None 1013 1013 1014 1014 1015 def _makeFields(self, options, values):1016 fields = []1017 for name, value in values.iteritems():1018 if name not in options:1019 continue1020 1021 option = {'var': name}1022 option.update(options[name])1023 if isinstance(value, list):1024 option['values'] = value1025 else:1026 option['value'] = value1027 fields.append(data_form.Field.fromDict(option))1028 return fields1029 1030 1031 1015 def _formFromConfiguration(self, resource, values): 1032 options = resource.getConfigurationOptions() 1033 fields = self._makeFields(options, values) 1016 fieldDefs = resource.getConfigurationOptions() 1034 1017 form = data_form.Form(formType="form", 1035 formNamespace=NS_PUBSUB_NODE_CONFIG, 1036 fields=fields) 1037 1018 formNamespace=NS_PUBSUB_NODE_CONFIG) 1019 form.makeFields(values, fieldDefs) 1038 1020 return form 1039 1021 1040 1022 -
wokkel/test/test_data_form.py
diff -r ba58db23e8b9 wokkel/test/test_data_form.py
a b 787 787 self.assertRaises(data_form.Error, form.addField, field2) 788 788 789 789 790 def test_removeField(self): 791 """ 792 A removed field should not occur in fieldList. 793 """ 794 form = data_form.Form('result') 795 field = data_form.Field('fixed', value='Section 1') 796 form.addField(field) 797 form.removeField(field) 798 self.assertNotIn(field, form.fieldList) 799 800 801 def test_removeFieldNamed(self): 802 """ 803 A removed named field should not occur in fields. 804 """ 805 form = data_form.Form('result') 806 field = data_form.Field(var='test', value='test1') 807 form.addField(field) 808 form.removeField(field) 809 self.assertNotIn('test', form.fields) 810 811 812 def test_makeField(self): 813 """ 814 Fields can be created from a dict of values and a dict of field defs. 815 """ 816 fieldDefs = { 817 "pubsub#persist_items": 818 {"type": "boolean", 819 "label": "Persist items to storage"}, 820 "pubsub#deliver_payloads": 821 {"type": "boolean", 822 "label": "Deliver payloads with event notifications"}, 823 "pubsub#creator": 824 {"type": "jid-single", 825 "label": "The JID of the node creator"}, 826 "pubsub#description": 827 {"type": "text-single", 828 "label": "A description of the node"}, 829 "pubsub#owner": 830 {"type": "jid-single", 831 "label": "Owner of the node"}, 832 } 833 values = {'pubsub#deliver_payloads': '0', 834 'pubsub#persist_items': True, 835 'pubsub#description': 'a great node', 836 'pubsub#owner': jid.JID('user@example.org'), 837 'x-myfield': ['a', 'b']} 838 839 form = data_form.Form('submit') 840 form.makeFields(values, fieldDefs) 841 842 # Check that the expected fields have been created 843 self.assertIn('pubsub#deliver_payloads', form.fields) 844 self.assertIn('pubsub#persist_items', form.fields) 845 self.assertIn('pubsub#description', form.fields) 846 self.assertIn('pubsub#owner', form.fields) 847 848 # This field is not created because there is no value for it. 849 self.assertNotIn('pubsub#creator', form.fields) 850 851 # This field is not created because it does not appear in fieldDefs 852 self.assertNotIn('x-myfield', form.fields) 853 854 # Check properties the created fields 855 self.assertEqual('boolean', 856 form.fields['pubsub#deliver_payloads'].fieldType) 857 self.assertEqual('0', 858 form.fields['pubsub#deliver_payloads'].value) 859 self.assertEqual('Deliver payloads with event notifications', 860 form.fields['pubsub#deliver_payloads'].label) 861 self.assertEqual(True, 862 form.fields['pubsub#persist_items'].value) 863 864 865 866 867 def test_makeFieldsUnknownTypeJID(self): 868 """ 869 Without type, a single JID value sets field type jid-single. 870 """ 871 values = {'pubsub#creator': jid.JID('user@example.org')} 872 form = data_form.Form('result') 873 form.makeFields(values) 874 field = form.fields['pubsub#creator'] 875 self.assertEqual('jid-single', field.fieldType) 876 877 878 def test_makeFieldsUnknownTypeJIDMulti(self): 879 """ 880 Without type, multiple JID values sets field type jid-multi. 881 """ 882 values = {'pubsub#contact': [jid.JID('user@example.org'), 883 jid.JID('other@example.org')]} 884 form = data_form.Form('result') 885 form.makeFields(values) 886 field = form.fields['pubsub#contact'] 887 self.assertEqual('jid-multi', field.fieldType) 888 889 890 def test_makeFieldsUnknownTypeBoolean(self): 891 """ 892 Without type, a boolean value sets field type boolean. 893 """ 894 values = {'pubsub#persist_items': True} 895 form = data_form.Form('result') 896 form.makeFields(values) 897 field = form.fields['pubsub#persist_items'] 898 self.assertEqual('boolean', field.fieldType) 899 900 901 def test_makeFieldsUnknownTypeListMulti(self): 902 """ 903 Without type, multiple values sets field type list-multi. 904 """ 905 values = {'pubsub#show-values': ['chat', 'online', 'away']} 906 form = data_form.Form('result') 907 form.makeFields(values) 908 field = form.fields['pubsub#show-values'] 909 self.assertEqual('list-multi', field.fieldType) 910 911 790 912 def test_getValues(self): 791 913 """ 792 914 Each named field is represented in the values, keyed by name. … … 834 956 form = data_form.Form('submit', fields=fields) 835 957 values = form.getValues() 836 958 self.assertEqual({'features': 'news'}, values) 959 960 961 def test_typeCheckKnownFieldChecked(self): 962 """ 963 Known fields are type checked. 964 """ 965 checked = [] 966 fieldDefs = {"pubsub#description": 967 {"type": "text-single", 968 "label": "A description of the node"}} 969 form = data_form.Form('submit') 970 form.addField(data_form.Field(var='pubsub#description', 971 value='a node')) 972 field = form.fields['pubsub#description'] 973 field.typeCheck = lambda : checked.append(None) 974 form.typeCheck(fieldDefs) 975 976 self.assertEqual([None], checked) 977 978 979 def test_typeCheckKnownFieldNoType(self): 980 """ 981 Known fields without a type get the type of the field definition. 982 """ 983 checked = [] 984 fieldDefs = {"pubsub#description": 985 {"type": "text-single", 986 "label": "A description of the node"}} 987 form = data_form.Form('submit') 988 form.addField(data_form.Field(None, var='pubsub#description', 989 value='a node')) 990 field = form.fields['pubsub#description'] 991 field.typeCheck = lambda : checked.append(None) 992 form.typeCheck(fieldDefs) 993 994 self.assertEqual('text-single', field.fieldType) 995 self.assertEqual([None], checked) 996 997 998 def test_typeCheckWrongFieldType(self): 999 """ 1000 A field should have the same type as the field definition. 1001 """ 1002 checked = [] 1003 fieldDefs = {"pubsub#description": 1004 {"type": "text-single", 1005 "label": "A description of the node"}} 1006 form = data_form.Form('submit') 1007 form.addField(data_form.Field('list-single', var='pubsub#description', 1008 value='a node')) 1009 field = form.fields['pubsub#description'] 1010 field.typeCheck = lambda : checked.append(None) 1011 1012 self.assertRaises(TypeError, form.typeCheck, fieldDefs) 1013 self.assertEqual([], checked) 1014 1015 1016 def test_typeCheckDefaultTextSingle(self): 1017 """ 1018 If a field definition has no type, use text-single. 1019 """ 1020 checked = [] 1021 fieldDefs = {"pubsub#description": 1022 {"label": "A description of the node"}} 1023 form = data_form.Form('submit') 1024 form.addField(data_form.Field('text-single', var='pubsub#description', 1025 value='a node')) 1026 field = form.fields['pubsub#description'] 1027 field.typeCheck = lambda : checked.append(None) 1028 form.typeCheck(fieldDefs) 1029 1030 self.assertEqual([None], checked) 1031 1032 1033 def test_typeCheckUnknown(self): 1034 """ 1035 Unkown fields are not checked, but not removed if filterUnknown False. 1036 """ 1037 checked = [] 1038 fieldDefs = {} 1039 form = data_form.Form('submit') 1040 form.addField(data_form.Field('list-single', var='pubsub#description', 1041 value='a node')) 1042 field = form.fields['pubsub#description'] 1043 field.typeCheck = lambda : checked.append(None) 1044 form.typeCheck(fieldDefs, filterUnknown=False) 1045 1046 self.assertIn('pubsub#description', form.fields) 1047 self.assertEqual([], checked) 1048 1049 1050 def test_typeCheckUnknownRemoved(self): 1051 """ 1052 Unkown fields are not checked, and removed if filterUnknown True. 1053 """ 1054 checked = [] 1055 fieldDefs = {} 1056 form = data_form.Form('submit') 1057 form.addField(data_form.Field('list-single', var='pubsub#description', 1058 value='a node')) 1059 field = form.fields['pubsub#description'] 1060 field.typeCheck = lambda : checked.append(None) 1061 form.typeCheck(fieldDefs, filterUnknown=True) 1062 1063 self.assertNotIn('pubsub#description', form.fields) 1064 self.assertEqual([], checked) 1065 1066
Note: See TracBrowser
for help on using the repository browser.