comparison test/test_templating.py @ 8300:b99e76e76496

Make native date and number elements configurable Now for Number() and Integer() properties the browser-native number format can be configured with the use_browser_number_input config item in seciont [web]. The default is 'yes'. For Date() properties the config item is use_browser_date_input (also in section [web]) but the default is 'no'. In addition when defining Date() properties, these now have a parameter 'display_time' which defaults to 'yes' and a 'format' parameter which defaults to None. These set defaults for the field() method of the DateHTMLProperty which have the same parameters (but the display_time parameter of field() takes a boolean, not 'yes'/'no').
author Ralf Schlatterbeck <rsc@runtux.com>
date Wed, 19 Feb 2025 12:38:06 +0100
parents 46886073c665
children a81a3cd067fa
comparison
equal deleted inserted replaced
8299:43899d99fc4d 8300:b99e76e76496
44 reason='markdown not available')) 44 reason='markdown not available'))
45 45
46 from roundup.anypy.strings import u2s, s2u 46 from roundup.anypy.strings import u2s, s2u
47 47
48 from roundup.backends.sessions_common import SessionCommon 48 from roundup.backends.sessions_common import SessionCommon
49
50 class MockConfig(dict):
51 def __getattr__(self, name):
52 try:
53 return self[name]
54 except KeyError as err:
55 raise AttributeError(err)
49 56
50 class MockDatabase(MockNull, SessionCommon): 57 class MockDatabase(MockNull, SessionCommon):
51 def getclass(self, name): 58 def getclass(self, name):
52 # limit class names 59 # limit class names
53 if name not in [ 'issue', 'user', 'status' ]: 60 if name not in [ 'issue', 'user', 'status' ]:
93 self.client.form = self.form 100 self.client.form = self.form
94 101
95 # add client props for testing anti_csrf_nonce 102 # add client props for testing anti_csrf_nonce
96 self.client.session_api = MockNull(_sid="1234567890") 103 self.client.session_api = MockNull(_sid="1234567890")
97 self.client.db.getuid = lambda : 10 104 self.client.db.getuid = lambda : 10
98 self.client.db.config = {'WEB_CSRF_TOKEN_LIFETIME': 10, 'MARKDOWN_BREAK_ON_NEWLINE': False } 105 self.client.db.config = MockConfig (
106 {'WEB_CSRF_TOKEN_LIFETIME': 10,
107 'MARKDOWN_BREAK_ON_NEWLINE': False })
99 108
100 class HTMLDatabaseTestCase(TemplatingTestCase): 109 class HTMLDatabaseTestCase(TemplatingTestCase):
101 def test_HTMLDatabase___getitem__(self): 110 def test_HTMLDatabase___getitem__(self):
102 db = HTMLDatabase(self.client) 111 db = HTMLDatabase(self.client)
103 self.assertTrue(isinstance(db['issue'], HTMLClass)) 112 self.assertTrue(isinstance(db['issue'], HTMLClass))
348 expected_val = 2345678.23457 357 expected_val = 2345678.23457
349 358
350 # test with number 359 # test with number
351 p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test', 360 p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
352 2345678.2345678) 361 2345678.2345678)
362 self.client.db.config['WEB_USE_BROWSER_NUMBER_INPUT'] = False
353 self.assertEqual(p.field(), 363 self.assertEqual(p.field(),
354 ('<input id="testnum1@test" name="testnum1@test" size="30" type="number" ' 364 ('<input id="testnum1@test" name="testnum1@test" '
355 'value="%s">')%expected_val) 365 'size="30" type="text" value="%s">')%expected_val)
366 self.client.db.config['WEB_USE_BROWSER_NUMBER_INPUT'] = True
367 self.assertEqual(p.field(),
368 ('<input id="testnum1@test" name="testnum1@test" '
369 'size="30" type="number" value="%s">')%expected_val)
356 self.assertEqual(p.field(size=10), 370 self.assertEqual(p.field(size=10),
357 ('<input id="testnum1@test" name="testnum1@test" size="10" type="number" ' 371 ('<input id="testnum1@test" name="testnum1@test" '
358 'value="%s">')%expected_val) 372 'size="10" type="number" value="%s">')%expected_val)
359 self.assertEqual(p.field(size=10, dataprop="foo", dataprop2=5), 373 self.assertEqual(p.field(size=10, dataprop="foo", dataprop2=5),
360 ('<input dataprop="foo" dataprop2="5" ' 374 ('<input dataprop="foo" dataprop2="5" '
361 'id="testnum1@test" name="testnum1@test" ' 375 'id="testnum1@test" name="testnum1@test" '
362 'size="10" type="number" ' 376 'size="10" type="number" '
363 'value="%s">'%expected_val)) 377 'value="%s">'%expected_val))
878 892
879 def tearDown(self): 893 def tearDown(self):
880 self.client.db.close() 894 self.client.db.close()
881 memorydb.db_nuke('') 895 memorydb.db_nuke('')
882 896
897 def exp_classhelp(self, cls='issue', prop='deadline', dlm='.'):
898 value = dlm.join (('2021-01-01', '11:22:10'))
899 return ('<a class="classhelp" data-calurl="%(cls)s?'
900 '@template=calendar&amp;amp;property=%(prop)s&amp;amp;'
901 'form=itemSynopsis&amp;date=%(value)s" '
902 'data-height="200" data-width="300" href="javascript:help_window'
903 '(\'%(cls)s?@template=calendar&amp;property=%(prop)s&amp;'
904 'form=itemSynopsis&date=%(value)s\', 300, 200)">(cal)</a>'
905 ) % {'cls': cls, 'prop': prop, 'value': value}
906
883 def test_DateHTMLWithDate(self): 907 def test_DateHTMLWithDate(self):
884 """Test methods when DateHTMLProperty._value is a hyperdb.Date() 908 """Test methods when DateHTMLProperty._value is a hyperdb.Date()
885 """ 909 """
910 self.client.db.config['WEB_USE_BROWSER_DATE_INPUT'] = True
886 test_datestring = self.test_datestring 911 test_datestring = self.test_datestring
887 test_Date = self.client.db.issue.get("1", 'deadline') 912 test_Date = self.client.db.issue.get("1", 'deadline')
888 test_hyperdbDate = self.client.db.issue.getprops("1")['deadline'] 913 test_hyperdbDate = self.client.db.issue.getprops("1")['deadline']
889 914
890 self.client.classname = "issue" 915 self.client.classname = "issue"
899 self.assertEqual(d.pretty("%2d %B %Y"), "01 January 2021") 924 self.assertEqual(d.pretty("%2d %B %Y"), "01 January 2021")
900 self.assertEqual(d.pretty(format="%Y-%m"), "2021-01") 925 self.assertEqual(d.pretty(format="%Y-%m"), "2021-01")
901 self.assertEqual(d.plain(), "2021-01-01.13:22:10") 926 self.assertEqual(d.plain(), "2021-01-01.13:22:10")
902 self.assertEqual(d.local("-4").plain(), "2021-01-01.07:22:10") 927 self.assertEqual(d.local("-4").plain(), "2021-01-01.07:22:10")
903 input_expected = """<input id="issue1@deadline" name="issue1@deadline" size="30" type="date" value="2021-01-01">""" 928 input_expected = """<input id="issue1@deadline" name="issue1@deadline" size="30" type="date" value="2021-01-01">"""
929 self.assertEqual(d.field(display_time=False), input_expected)
930
931 input_expected = '<input id="issue1@deadline" name="issue1@deadline" '\
932 'size="30" type="datetime-local" value="2021-01-01T13:22:10">'
904 self.assertEqual(d.field(), input_expected) 933 self.assertEqual(d.field(), input_expected)
905 self.assertEqual(d.field_time(type="date"), input_expected) 934
906 935 input_expected = '<input id="issue1@deadline" name="issue1@deadline" '\
907 input_expected = """<input id="issue1@deadline" name="issue1@deadline" size="30" type="datetime-local" value="2021-01-01T13:22:10">""" 936 'size="30" type="text" value="2021-01-01.13:22:10">'
908 self.assertEqual(d.field(type="datetime-local"), input_expected) 937 field = d.field(format='%Y-%m-%d.%H:%M:%S', popcal=False)
909 self.assertEqual(d.field_time(), input_expected) 938 self.assertEqual(field, input_expected)
910
911 input_expected = """<input id="issue1@deadline" name="issue1@deadline" size="30" type="text" value="2021-01-01.13:22:10">"""
912 self.assertEqual(d.field(type="text"), input_expected)
913 self.assertEqual(d.field_time(type="text"), input_expected)
914 939
915 # test with format 940 # test with format
916 input_expected = """<input id="issue1@deadline" name="issue1@deadline" size="30" type="text" value="2021-01"><a class="classhelp" data-calurl="issue?@template=calendar&amp;amp;property=deadline&amp;amp;form=itemSynopsis&amp;date=2021-01-01.11:22:10" data-height="200" data-width="300" href="javascript:help_window(\'issue?@template=calendar&amp;property=deadline&amp;form=itemSynopsis&date=2021-01-01.11:22:10\', 300, 200)">(cal)</a>""" 941 input_expected = '<input id="issue1@deadline" name="issue1@deadline" '\
917 942 'size="30" type="text" value="2021-01">' + self.exp_classhelp()
918 self._caplog.clear() 943
919 with self._caplog.at_level(logging.WARNING, 944 self.assertEqual(d.field(format="%Y-%m"), input_expected)
920 logger="roundup"): 945
921 input = d.field(format="%Y-%m") 946 input_expected = '<input id="issue1@deadline" name="issue1@deadline" '\
922 self.assertEqual(input_expected, input) 947 'size="30" type="text" value="2021-01">'
923 948
924 # name used for logging 949 input = d.field(format="%Y-%m", popcal=False)
925 log_expected = """Format '%Y-%m' prevents use of modern date input. Remove format from field() call in template issue.item. Using text input.""" 950 self.assertEqual(input, input_expected)
926 self.assertEqual(self._caplog.record_tuples[0][2], log_expected)
927 # severity ERROR = 40
928 self.assertEqual(self._caplog.record_tuples[0][1], 30,
929 msg="logging level != 30 (WARNING)")
930
931 # test with format and popcal=None
932 input_expected = """<input id="issue1@deadline" name="issue1@deadline" size="30" type="text" value="2021-01">"""
933
934 self._caplog.clear()
935 with self._caplog.at_level(logging.WARNING,
936 logger="roundup"):
937 input = d.field(format="%Y-%m", popcal=False)
938 self.assertEqual(input_expected, input)
939
940 # name used for logging
941 log_expected = """Format '%Y-%m' prevents use of modern date input. Remove format from field() call in template issue.item. Using text input."""
942 self.assertEqual(self._caplog.record_tuples[0][2], log_expected)
943 # severity ERROR = 40
944 self.assertEqual(self._caplog.record_tuples[0][1], 30,
945 msg="logging level != 30 (WARNING)")
946
947 # test with format, type=text and popcal=None
948 input_expected = """<input id="issue1@deadline" name="issue1@deadline" size="30" type="text" value="2021-01">"""
949
950 self._caplog.clear()
951 with self._caplog.at_level(logging.WARNING,
952 logger="roundup"):
953 input = d.field(type="text", format="%Y-%m", popcal=False )
954 self.assertEqual(input_expected, input)
955
956 self.assertEqual(self._caplog.records, [])
957 951
958 def test_DateHTMLWithText(self): 952 def test_DateHTMLWithText(self):
959 """Test methods when DateHTMLProperty._value is a string 953 """Test methods when DateHTMLProperty._value is a string
960 rather than a hyperdb.Date() 954 rather than a hyperdb.Date()
961 """ 955 """
962 test_datestring = "2021-01-01 11:22:10" 956 test_datestring = "2021-01-01 11:22:10"
963 test_date = hyperdb.Date("2") 957 test_date = hyperdb.Date("2")
964 958
965 self.form.list.append(MiniFieldStorage("test1@test", test_datestring)) 959 self.form.list.append(MiniFieldStorage("test1@test", test_datestring))
966 self.client._props=test_date 960 self.client._props=test_date
961 self.client.db.config['WEB_USE_BROWSER_DATE_INPUT'] = False
967 962
968 self.client.db.classes = dict \ 963 self.client.db.classes = dict \
969 ( test = MockNull(getprops = lambda : test_date) 964 ( test = MockNull(getprops = lambda : test_date)
970 ) 965 )
971 966
977 d = DateHTMLProperty(self.client, 'test', '1', self.client._props, 972 d = DateHTMLProperty(self.client, 'test', '1', self.client._props,
978 'test', '') 973 'test', '')
979 self.assertIs(type(d._value), str) 974 self.assertIs(type(d._value), str)
980 self.assertEqual(d.pretty(), "2021-01-01 11:22:10") 975 self.assertEqual(d.pretty(), "2021-01-01 11:22:10")
981 self.assertEqual(d.plain(), "2021-01-01 11:22:10") 976 self.assertEqual(d.plain(), "2021-01-01 11:22:10")
982 input = """<input id="test1@test" name="test1@test" size="30" type="date" value="2021-01-01 11:22:10">""" 977 input_expected = '<input id="test1@test" name="test1@test" size="30" '\
983 self.assertEqual(d.field(), input) 978 'type="text" value="2021-01-01 11:22:10">'
984 979 self.assertEqual(d.field(popcal=False), input_expected)
985 980 self.client.db.config['WEB_USE_BROWSER_DATE_INPUT'] = True
986 input_expected = """<input id="test1@test" name="test1@test" size="40" type="date" value="2021-01-01 11:22:10">""" 981 input_expected = '<input id="test1@test" name="test1@test" size="30" '\
987 self.assertEqual(d.field(size=40), input_expected) 982 'type="datetime-local" value="2021-01-01 11:22:10">'
988 983 self.assertEqual(d.field(), input_expected)
989 input_expected = """<input id="test1@test" name="test1@test" size="30" type="text" value="2021-01-01 11:22:10"><a class="classhelp" data-calurl="test?@template=calendar&amp;amp;property=test&amp;amp;form=itemSynopsis&amp;date=2021-01-01 11:22:10" data-height="200" data-width="300" href="javascript:help_window(\'test?@template=calendar&amp;property=test&amp;form=itemSynopsis&date=2021-01-01 11:22:10\', 300, 200)">(cal)</a>""" 984 self.client.db.config['WEB_USE_BROWSER_DATE_INPUT'] = False
990 with self._caplog.at_level(logging.WARNING, 985
991 logger="roundup"): 986 input_expected = '<input id="test1@test" name="test1@test" size="40" '\
992 input = d.field(format="%Y-%m") 987 'type="text" value="2021-01-01 11:22:10">'
993 self.assertEqual(input_expected, input) 988 self.assertEqual(d.field(size=40, popcal=False), input_expected)
994 989
995 # name used for logging 990 input_expected = ('<input id="test1@test" name="test1@test" size="30" '
996 log_expected = """Format '%Y-%m' prevents use of modern date input. Remove format from field() call in template test.item. Using text input.""" 991 'type="text" value="2021-01-01 11:22:10">'
997 self.assertEqual(self._caplog.record_tuples[0][2], log_expected) 992 + self.exp_classhelp(cls='test', prop='test', dlm=' '))
998 # severity ERROR = 40 993 self.maxDiff=None
999 self.assertEqual(self._caplog.record_tuples[0][1], 30, 994 self.assertEqual(d.field(format="%Y-%m"), input_expected)
1000 msg="logging level != 30 (WARNING)") 995
1001 996 # format always uses type="text" even when date input is set
1002 """with self.assertRaises(ValueError) as e: 997 self.client.db.config['WEB_USE_BROWSER_DATE_INPUT'] = True
1003 d.field(format="%Y-%m") 998 result = d.field(format="%Y-%m-%d", popcal=False)
1004 self.assertIn("'%Y-%m'", e.exception.args[0]) 999 input_expected = '<input id="test1@test" name="test1@test" size="30" '\
1005 self.assertIn("'date'", e.exception.args[0])""" 1000 'type="text" value="2021-01-01 11:22:10">'
1006
1007
1008 # format matches rfc format, so this should pass
1009 result = d.field(format="%Y-%m-%d")
1010 input_expected = """<input id="test1@test" name="test1@test" size="30" type="date" value="2021-01-01 11:22:10">"""
1011 self.assertEqual(result, input_expected) 1001 self.assertEqual(result, input_expected)
1012 1002
1013 input_expected = """<input id="test1@test" name="test1@test" size="30" type="text" value="2021-01-01 11:22:10"><a class="classhelp" data-calurl="test?@template=calendar&amp;amp;property=test&amp;amp;form=itemSynopsis&amp;date=2021-01-01 11:22:10" data-height="200" data-width="300" href="javascript:help_window(\'test?@template=calendar&amp;property=test&amp;form=itemSynopsis&date=2021-01-01 11:22:10\', 300, 200)">(cal)</a>""" 1003 input_expected = ('<input id="test1@test" name="test1@test" size="30" '
1014 with self._caplog.at_level(logging.WARNING, 1004 'type="text" value="2021-01-01 11:22:10">'
1015 logger="roundup"): 1005 + self.exp_classhelp(cls='test', prop='test', dlm=' '))
1016 input = d.field(format="%Y-%m", type="datetime-local") 1006 self.assertEqual(d.field(format="%Y-%m"), input_expected)
1017 self.assertEqual(input_expected, input) 1007
1018 1008 result = d.field(format="%Y-%m-%dT%H:%M:%S", popcal=False)
1019 # name used for logging 1009 input_expected = '<input id="test1@test" name="test1@test" size="30" '\
1020 log_expected = """Format '%Y-%m' prevents use of modern date input. Remove format from field() call in template test.item. Using text input.""" 1010 'type="text" value="2021-01-01 11:22:10">'
1021 self.assertEqual(self._caplog.record_tuples[0][2], log_expected)
1022 # severity ERROR = 40
1023 self.assertEqual(self._caplog.record_tuples[0][1], 30,
1024 msg="logging level != 30 (WARNING)")
1025
1026 """
1027 with self.assertRaises(ValueError) as e:
1028 d.field(format="%Y-%m", type="datetime-local")
1029 self.assertIn("'%Y-%m'", e.exception.args[0])
1030 self.assertIn("'datetime-local'", e.exception.args[0])
1031 """
1032
1033 # format matches rfc, so this should pass
1034 result = d.field(type="datetime-local", format="%Y-%m-%dT%H:%M:%S")
1035 input_expected = """<input id="test1@test" name="test1@test" size="30" type="datetime-local" value="2021-01-01 11:22:10">"""
1036 self.assertEqual(result, input_expected) 1011 self.assertEqual(result, input_expected)
1037 1012
1038 # common markdown test cases 1013 # common markdown test cases
1039 class MarkdownTests: 1014 class MarkdownTests:
1040 def mangleMarkdown2(self, s): 1015 def mangleMarkdown2(self, s):

Roundup Issue Tracker: http://roundup-tracker.org/