fix: add grid renderers for bool, currency, quantity
also set bool renderer by default when possible
This commit is contained in:
		
							parent
							
								
									08a895a07b
								
							
						
					
					
						commit
						a612bf3846
					
				
					 2 changed files with 130 additions and 14 deletions
				
			
		| 
						 | 
				
			
			@ -116,7 +116,8 @@ class Grid:
 | 
			
		|||
 | 
			
		||||
       Dict of column (cell) value renderer overrides.
 | 
			
		||||
 | 
			
		||||
       See also :meth:`set_renderer()`.
 | 
			
		||||
       See also :meth:`set_renderer()` and
 | 
			
		||||
       :meth:`set_default_renderers()`.
 | 
			
		||||
 | 
			
		||||
    .. attribute:: row_class
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -602,15 +603,18 @@ class Grid:
 | 
			
		|||
        """
 | 
			
		||||
        Set default column value renderers, where applicable.
 | 
			
		||||
 | 
			
		||||
        This will add new entries to :attr:`renderers` for columns
 | 
			
		||||
        whose data type implies a default renderer should be used.
 | 
			
		||||
        This is generally only possible if :attr:`model_class` is set
 | 
			
		||||
        to a valid SQLAlchemy mapped class.
 | 
			
		||||
        This is called automatically from the class constructor.  It
 | 
			
		||||
        will add new entries to :attr:`renderers` for columns whose
 | 
			
		||||
        data type implies a default renderer.  This is only possible
 | 
			
		||||
        if :attr:`model_class` is set to a SQLAlchemy mapped class.
 | 
			
		||||
 | 
			
		||||
        This (for now?) only looks for
 | 
			
		||||
        :class:`sqlalchemy:sqlalchemy.types.DateTime` columns and if
 | 
			
		||||
        any are found, they are configured to use
 | 
			
		||||
        :meth:`render_datetime()`.
 | 
			
		||||
        This only looks for a couple of data types, and configures as
 | 
			
		||||
        follows:
 | 
			
		||||
 | 
			
		||||
        * :class:`sqlalchemy:sqlalchemy.types.Boolean` ->
 | 
			
		||||
          :meth:`render_boolean()`
 | 
			
		||||
        * :class:`sqlalchemy:sqlalchemy.types.DateTime` ->
 | 
			
		||||
          :meth:`render_datetime()`
 | 
			
		||||
        """
 | 
			
		||||
        if not self.model_class:
 | 
			
		||||
            return
 | 
			
		||||
| 
						 | 
				
			
			@ -626,6 +630,8 @@ class Grid:
 | 
			
		|||
                    column = prop.columns[0]
 | 
			
		||||
                    if isinstance(column.type, sa.DateTime):
 | 
			
		||||
                        self.set_renderer(key, self.render_datetime)
 | 
			
		||||
                    elif isinstance(column.type, sa.Boolean):
 | 
			
		||||
                        self.set_renderer(key, self.render_boolean)
 | 
			
		||||
 | 
			
		||||
    def set_link(self, key, link=True):
 | 
			
		||||
        """
 | 
			
		||||
| 
						 | 
				
			
			@ -1753,23 +1759,65 @@ class Grid:
 | 
			
		|||
    # rendering methods
 | 
			
		||||
    ##############################
 | 
			
		||||
 | 
			
		||||
    def render_boolean(self, obj, key, value):
 | 
			
		||||
        """
 | 
			
		||||
        Column renderer for boolean values.
 | 
			
		||||
 | 
			
		||||
        This calls
 | 
			
		||||
        :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_boolean()`
 | 
			
		||||
        for the return value.
 | 
			
		||||
 | 
			
		||||
        This may be used automatically per
 | 
			
		||||
        :meth:`set_default_renderers()` or you can use it explicitly::
 | 
			
		||||
 | 
			
		||||
            grid.set_renderer('foo', grid.render_boolean)
 | 
			
		||||
        """
 | 
			
		||||
        return self.app.render_boolean(value)
 | 
			
		||||
 | 
			
		||||
    def render_currency(self, obj, key, value):
 | 
			
		||||
        """
 | 
			
		||||
        Column renderer for currency values.
 | 
			
		||||
 | 
			
		||||
        This calls
 | 
			
		||||
        :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_currency()`
 | 
			
		||||
        for the return value.
 | 
			
		||||
 | 
			
		||||
        This is not used automatically but you can use it explicitly::
 | 
			
		||||
 | 
			
		||||
            grid.set_renderer('foo', grid.render_currency)
 | 
			
		||||
        """
 | 
			
		||||
        return self.app.render_currency(value)
 | 
			
		||||
 | 
			
		||||
    def render_datetime(self, obj, key, value):
 | 
			
		||||
        """
 | 
			
		||||
        Default cell value renderer for
 | 
			
		||||
        :class:`sqlalchemy:sqlalchemy.types.DateTime` columns, which
 | 
			
		||||
        calls
 | 
			
		||||
        Column renderer for :class:`python:datetime.datetime` values.
 | 
			
		||||
 | 
			
		||||
        This calls
 | 
			
		||||
        :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_datetime()`
 | 
			
		||||
        for the return value.
 | 
			
		||||
 | 
			
		||||
        This may be used automatically per
 | 
			
		||||
        :meth:`set_default_renderers()` or you can use it explicitly
 | 
			
		||||
        for any :class:`python:datetime.datetime` column with::
 | 
			
		||||
        :meth:`set_default_renderers()` or you can use it explicitly::
 | 
			
		||||
 | 
			
		||||
            grid.set_renderer('foo', grid.render_datetime)
 | 
			
		||||
        """
 | 
			
		||||
        dt = getattr(obj, key)
 | 
			
		||||
        return self.app.render_datetime(dt)
 | 
			
		||||
 | 
			
		||||
    def render_quantity(self, obj, key, value):
 | 
			
		||||
        """
 | 
			
		||||
        Column renderer for quantity values.
 | 
			
		||||
 | 
			
		||||
        This calls
 | 
			
		||||
        :meth:`~wuttjamaican:wuttjamaican.app.AppHandler.render_quantity()`
 | 
			
		||||
        for the return value.
 | 
			
		||||
 | 
			
		||||
        This is not used automatically but you can use it explicitly::
 | 
			
		||||
 | 
			
		||||
            grid.set_renderer('foo', grid.render_quantity)
 | 
			
		||||
        """
 | 
			
		||||
        return self.app.render_quantity(value)
 | 
			
		||||
 | 
			
		||||
    def render_table_element(
 | 
			
		||||
            self,
 | 
			
		||||
            form=None,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
# -*- coding: utf-8; -*-
 | 
			
		||||
 | 
			
		||||
import datetime
 | 
			
		||||
import decimal
 | 
			
		||||
from unittest import TestCase
 | 
			
		||||
from unittest.mock import patch, MagicMock
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -232,6 +233,17 @@ class TestGrid(WebTestCase):
 | 
			
		|||
        self.assertIn('created', grid.renderers)
 | 
			
		||||
        self.assertIs(grid.renderers['created'], myrender)
 | 
			
		||||
 | 
			
		||||
        # renderer set for boolean mapped field
 | 
			
		||||
        grid = self.make_grid(model_class=model.Upgrade)
 | 
			
		||||
        self.assertIn('executing', grid.renderers)
 | 
			
		||||
        self.assertIsNot(grid.renderers['executing'], myrender)
 | 
			
		||||
 | 
			
		||||
        # renderer *not* set for boolean, if override present
 | 
			
		||||
        grid = self.make_grid(model_class=model.Upgrade,
 | 
			
		||||
                              renderers={'executing': myrender})
 | 
			
		||||
        self.assertIn('executing', grid.renderers)
 | 
			
		||||
        self.assertIs(grid.renderers['executing'], myrender)
 | 
			
		||||
 | 
			
		||||
    def test_linked_columns(self):
 | 
			
		||||
        grid = self.make_grid(columns=['foo', 'bar'])
 | 
			
		||||
        self.assertEqual(grid.linked_columns, [])
 | 
			
		||||
| 
						 | 
				
			
			@ -1331,6 +1343,62 @@ class TestGrid(WebTestCase):
 | 
			
		|||
    # rendering methods
 | 
			
		||||
    ##############################
 | 
			
		||||
 | 
			
		||||
    def test_render_boolean(self):
 | 
			
		||||
        grid = self.make_grid(columns=['foo', 'bar'])
 | 
			
		||||
 | 
			
		||||
        # null
 | 
			
		||||
        obj = MagicMock(foo=None)
 | 
			
		||||
        self.assertEqual(grid.render_boolean(obj, 'foo', None), "")
 | 
			
		||||
 | 
			
		||||
        # true
 | 
			
		||||
        obj = MagicMock(foo=True)
 | 
			
		||||
        self.assertEqual(grid.render_boolean(obj, 'foo', True), "Yes")
 | 
			
		||||
 | 
			
		||||
        # false
 | 
			
		||||
        obj = MagicMock(foo=False)
 | 
			
		||||
        self.assertEqual(grid.render_boolean(obj, 'foo', False), "No")
 | 
			
		||||
 | 
			
		||||
    def test_render_currency(self):
 | 
			
		||||
        grid = self.make_grid(columns=['foo', 'bar'])
 | 
			
		||||
        obj = MagicMock()
 | 
			
		||||
 | 
			
		||||
        # null
 | 
			
		||||
        self.assertEqual(grid.render_currency(obj, 'foo', None), '')
 | 
			
		||||
 | 
			
		||||
        # basic decimal example
 | 
			
		||||
        value = decimal.Decimal('42.00')
 | 
			
		||||
        self.assertEqual(grid.render_currency(obj, 'foo', value), '$42.00')
 | 
			
		||||
 | 
			
		||||
        # basic float example
 | 
			
		||||
        value = 42.00
 | 
			
		||||
        self.assertEqual(grid.render_currency(obj, 'foo', value), '$42.00')
 | 
			
		||||
 | 
			
		||||
        # decimal places will be rounded
 | 
			
		||||
        value = decimal.Decimal('42.12345')
 | 
			
		||||
        self.assertEqual(grid.render_currency(obj, 'foo', value), '$42.12')
 | 
			
		||||
 | 
			
		||||
        # negative numbers get parens
 | 
			
		||||
        value = decimal.Decimal('-42.42')
 | 
			
		||||
        self.assertEqual(grid.render_currency(obj, 'foo', value), '($42.42)')
 | 
			
		||||
 | 
			
		||||
    def test_render_quantity(self):
 | 
			
		||||
        grid = self.make_grid(columns=['foo', 'bar'])
 | 
			
		||||
        obj = MagicMock()
 | 
			
		||||
 | 
			
		||||
        # null
 | 
			
		||||
        self.assertEqual(grid.render_quantity(obj, 'foo', None), "")
 | 
			
		||||
 | 
			
		||||
        # integer decimals become integers
 | 
			
		||||
        value = decimal.Decimal('1.000')
 | 
			
		||||
        self.assertEqual(grid.render_quantity(obj, 'foo', value), "1")
 | 
			
		||||
 | 
			
		||||
        # but decimal places are preserved
 | 
			
		||||
        value = decimal.Decimal('1.234')
 | 
			
		||||
        self.assertEqual(grid.render_quantity(obj ,'foo', value), "1.234")
 | 
			
		||||
 | 
			
		||||
        # zero is *not* empty string (with this renderer)
 | 
			
		||||
        self.assertEqual(grid.render_quantity(obj, 'foo', 0), "0")
 | 
			
		||||
 | 
			
		||||
    def test_render_datetime(self):
 | 
			
		||||
        grid = self.make_grid(columns=['foo', 'bar'])
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue