Skip to content

Commit abb2146

Browse files
committed
issue2550559 - Pretty printing / formatting for Number types.
add pretty(format='%0.3f') method to NumberHTMLProperty.
1 parent f8aa34c commit abb2146

File tree

4 files changed

+146
-0
lines changed

4 files changed

+146
-0
lines changed

CHANGES.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ Features:
3737
pip, setting UID tracker is run under. (John Rouillard)
3838
- issue2551140 - Added redis as a session and otk database for use
3939
with anydbm and sqlite primary databases. (John Rouillard)
40+
- issue2550559 - Pretty printing / formatting for Number types.
41+
Added pretty(format='%0.3f') method to NumberHTMLProperty to
42+
print numeric values. If value is None, return empty string
43+
otherwise str() of value.
4044

4145
2022-07-13 2.2.0
4246

doc/customizing.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3397,6 +3397,11 @@ pretty Date properties - render the date as "dd Mon YYYY" (eg. "19
33973397
format (eg. "yesterday"). The format arguments are those used
33983398
in the standard ``strftime`` call (see the `Python Library
33993399
Reference: time module`__)
3400+
3401+
Number properties - takes a printf style format argument
3402+
(default: '%0.3f') and formats the number accordingly.
3403+
If the value can't be converted, '' is returned if the
3404+
value is ``None`` otherwise it is converted to a string.
34003405
popcal Generate a link to a popup calendar which may be used to
34013406
edit the date field, for example::
34023407

roundup/cgi/templating.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,6 +1957,21 @@ def plain(self, escape=0):
19571957

19581958
return str(self._value)
19591959

1960+
def pretty(self, format="%0.3f"):
1961+
'''Pretty print number using printf format specifier.
1962+
1963+
If value is not convertable, returns str(_value) or ""
1964+
if None.
1965+
'''
1966+
try:
1967+
return format%self._value
1968+
except TypeError:
1969+
value = self._value
1970+
if value is None:
1971+
return ''
1972+
else:
1973+
return str(value)
1974+
19601975
def field(self, size=30, **kwargs):
19611976
""" Render a form edit field for the property.
19621977

test/test_templating.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,128 @@ def test_anti_csrf_nonce(self):
305305
self.assertEqual(True,
306306
greater_than <= now - timestamp < (greater_than + 1) )
307307

308+
def test_number__int__(self):
309+
# test with number
310+
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
311+
2345678.2345678)
312+
self.assertEqual(p.__int__(), 2345678)
313+
314+
property = MockNull(get_default_value = lambda: None)
315+
p = NumberHTMLProperty(self.client, 'testnum', '1', property,
316+
'test', None)
317+
with self.assertRaises(TypeError) as e:
318+
p.__int__()
319+
320+
def test_number__float__(self):
321+
# test with number
322+
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
323+
2345678.2345678)
324+
self.assertEqual(p.__float__(), 2345678.2345678)
325+
326+
property = MockNull(get_default_value = lambda: None)
327+
p = NumberHTMLProperty(self.client, 'testnum', '1', property,
328+
'test', None)
329+
with self.assertRaises(TypeError) as e:
330+
p.__float__()
331+
332+
def test_number_field(self):
333+
import sys
334+
335+
_py3 = sys.version_info[0] > 2
336+
337+
# python2 truncates while python3 rounds. Sigh.
338+
if _py3:
339+
expected_val = 2345678.2345678
340+
else:
341+
expected_val = 2345678.23457
342+
343+
# test with number
344+
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
345+
2345678.2345678)
346+
self.assertEqual(p.field(),
347+
('<input name="testnum1@test" size="30" type="text" '
348+
'value="%s">')%expected_val)
349+
self.assertEqual(p.field(size=10),
350+
('<input name="testnum1@test" size="10" type="text" '
351+
'value="%s">')%expected_val)
352+
self.assertEqual(p.field(size=10, dataprop="foo", dataprop2=5),
353+
('<input dataprop="foo" dataprop2="5" '
354+
'name="testnum1@test" size="10" type="text" '
355+
'value="%s">'%expected_val))
356+
357+
self.assertEqual(p.field(size=10, klass="class1",
358+
**{ "class": "class2 class3",
359+
"data-prop": "foo",
360+
"data-prop2": 5}),
361+
('<input class="class2 class3" data-prop="foo" '
362+
'data-prop2="5" klass="class1" '
363+
'name="testnum1@test" size="10" type="text" '
364+
'value="%s">')%expected_val)
365+
366+
# get plain representation if user can't edit
367+
p.is_edit_ok = lambda: False
368+
self.assertEqual(p.field(), p.plain())
369+
370+
# test with string which is wrong type
371+
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
372+
"2345678.2345678")
373+
self.assertEqual(p.field(),
374+
('<input name="testnum1@test" size="30" type="text" '
375+
'value="2345678.2345678">'))
376+
377+
# test with None value, pretend property.__default_value = Null which
378+
# is the default. It would be returned by get_default_value
379+
# which I mock.
380+
property = MockNull(get_default_value = lambda: None)
381+
p = NumberHTMLProperty(self.client, 'testnum', '1', property,
382+
'test', None)
383+
self.assertEqual(p.field(),
384+
('<input name="testnum1@test" size="30" type="text" '
385+
'value="">'))
386+
387+
def test_number_plain(self):
388+
import sys
389+
390+
_py3 = sys.version_info[0] > 2
391+
392+
# python2 truncates while python3 rounds. Sigh.
393+
if _py3:
394+
expected_val = 2345678.2345678
395+
else:
396+
expected_val = 2345678.23457
397+
398+
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
399+
2345678.2345678)
400+
401+
self.assertEqual(p.plain(), "%s"%expected_val)
402+
403+
def test_number_pretty(self):
404+
# test with number
405+
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
406+
2345678.2345678)
407+
self.assertEqual(p.pretty(), "2345678.235")
408+
409+
# test with string which is wrong type
410+
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
411+
"2345678.2345678")
412+
self.assertEqual(p.pretty(), "2345678.2345678")
413+
414+
# test with boolean
415+
p = NumberHTMLProperty(self.client, 'testnum', '1', None, 'test',
416+
True)
417+
self.assertEqual(p.pretty(), "1.000")
418+
419+
# test with None value, pretend property.__default_value = Null which
420+
# is the default. It would be returned by get_default_value
421+
# which I mock.
422+
property = MockNull(get_default_value = lambda: None)
423+
p = NumberHTMLProperty(self.client, 'testnum', '1', property,
424+
'test', None)
425+
self.assertEqual(p.pretty(), '')
426+
427+
with self.assertRaises(ValueError) as e:
428+
p.pretty('%0.3')
429+
308430
def test_string_url_quote(self):
309431
''' test that urlquote quotes the string '''
310432
p = StringHTMLProperty(self.client, 'test', '1', None, 'test', 'test string< foo@bar')

0 commit comments

Comments
 (0)