diff --git a/CHANGELOG.md b/CHANGELOG.md index c991759..6de4999 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,16 +5,6 @@ All notable changes to wuttaweb will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## v0.8.0 (2024-08-15) - -### Feat - -- add form/grid label auto-overrides for master view - -### Fix - -- add `person` to template context for `PersonView.view_profile()` - ## v0.7.0 (2024-08-15) ### Feat diff --git a/pyproject.toml b/pyproject.toml index 118e712..35d94ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "WuttaWeb" -version = "0.8.0" +version = "0.7.0" description = "Web App for Wutta Framework" readme = "README.md" authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] @@ -39,7 +39,7 @@ dependencies = [ "pyramid_tm", "waitress", "WebHelpers2", - "WuttJamaican[db]>=0.12.0", + "WuttJamaican[db]>=0.11.1", "zope.sqlalchemy>=1.5", ] diff --git a/src/wuttaweb/forms/base.py b/src/wuttaweb/forms/base.py index 59cdc04..8ed17f8 100644 --- a/src/wuttaweb/forms/base.py +++ b/src/wuttaweb/forms/base.py @@ -435,14 +435,16 @@ class Form: Node overrides are tracked via :attr:`nodes`. """ - from wuttaweb.forms.schema import ObjectNode - if isinstance(nodeinfo, colander.SchemaNode): # assume nodeinfo is a complete node node = nodeinfo else: # assume nodeinfo is a schema type kwargs.setdefault('name', key) + + from wuttaweb.forms.schema import ObjectNode + + # node = colander.SchemaNode(nodeinfo, **kwargs) node = ObjectNode(nodeinfo, **kwargs) self.nodes[key] = node diff --git a/src/wuttaweb/forms/schema.py b/src/wuttaweb/forms/schema.py index 8c245f6..98ce0f1 100644 --- a/src/wuttaweb/forms/schema.py +++ b/src/wuttaweb/forms/schema.py @@ -59,16 +59,13 @@ class ObjectNode(colander.SchemaNode): :class:`ObjectRef`. If the node's type does not have a ``dictify()`` method, this - will just convert the object to a string and return that. + will raise ``NotImplementeError``. """ if hasattr(self.typ, 'dictify'): return self.typ.dictify(obj) - # TODO: this is better than raising an error, as it previously - # did, but seems like troubleshooting problems may often lead - # one here.. i suspect this needs to do something smarter but - # not sure what that is yet - return str(obj) + class_name = self.typ.__class__.__name__ + raise NotImplementedError(f"you must define {class_name}.dictify()") def objectify(self, value): """ diff --git a/src/wuttaweb/grids/base.py b/src/wuttaweb/grids/base.py index 740607c..1e793bd 100644 --- a/src/wuttaweb/grids/base.py +++ b/src/wuttaweb/grids/base.py @@ -82,12 +82,6 @@ class Grid: model records) or else an object capable of producing such a list, e.g. SQLAlchemy query. - .. attribute:: labels - - Dict of column label overrides. - - See also :meth:`get_label()` and :meth:`set_label()`. - .. attribute:: renderers Dict of column (cell) value renderer overrides. @@ -119,7 +113,6 @@ class Grid: key=None, columns=None, data=None, - labels={}, renderers={}, actions=[], linked_columns=[], @@ -129,7 +122,6 @@ class Grid: self.model_class = model_class self.key = key self.data = data - self.labels = labels or {} self.renderers = renderers or {} self.actions = actions or [] self.linked_columns = linked_columns or [] @@ -228,32 +220,6 @@ class Grid: if key in self.columns: self.columns.remove(key) - def set_label(self, key, label): - """ - Set/override the label for a column. - - :param key: Name of column. - - :param label: New label for the column header. - - See also :meth:`get_label()`. - - Label overrides are tracked via :attr:`labels`. - """ - self.labels[key] = label - - def get_label(self, key): - """ - Returns the label text for a given column. - - If no override is defined, the label is derived from ``key``. - - See also :meth:`set_label()`. - """ - if key in self.labels: - return self.labels[key] - return self.app.make_title(key) - def set_renderer(self, key, renderer, **kwargs): """ Set/override the value renderer for a column. @@ -410,7 +376,7 @@ class Grid: for name in self.columns: columns.append({ 'field': name, - 'label': self.get_label(name), + 'label': self.app.make_title(name), }) return columns @@ -464,7 +430,7 @@ class Grid: # customize value rendering where applicable for key in self.renderers: - value = record.get(key, None) + value = record[key] record[key] = self.renderers[key](original_record, key, value) # add action urls to each record diff --git a/src/wuttaweb/views/master.py b/src/wuttaweb/views/master.py index 1c7518d..fe4448f 100644 --- a/src/wuttaweb/views/master.py +++ b/src/wuttaweb/views/master.py @@ -33,7 +33,6 @@ from webhelpers2.html import HTML from wuttaweb.views import View from wuttaweb.util import get_form_data, get_model_fields from wuttaweb.db import Session -from wuttjamaican.util import get_class_hierarchy class MasterView(View): @@ -804,16 +803,6 @@ class MasterView(View): # support methods ############################## - def get_class_hierarchy(self, topfirst=True): - """ - Convenience to return a list of classes from which the current - class inherits. - - This is a wrapper around - :func:`wuttjamaican.util.get_class_hierarchy()`. - """ - return get_class_hierarchy(self.__class__, topfirst=topfirst) - def has_perm(self, name): """ Shortcut to check if current user has the given permission. @@ -960,60 +949,6 @@ class MasterView(View): route_prefix = self.get_route_prefix() return self.request.route_url(route_prefix, **kwargs) - def set_labels(self, obj): - """ - Set label overrides on a form or grid, based on what is - defined by the view class and its parent class(es). - - This is called automatically from :meth:`configure_grid()` and - :meth:`configure_form()`. - - This calls :meth:`collect_labels()` to find everything, then - it assigns the labels using one of (based on ``obj`` type): - - * :func:`wuttaweb.forms.base.Form.set_label()` - * :func:`wuttaweb.grids.base.Grid.set_label()` - - :param obj: Either a :class:`~wuttaweb.grids.base.Grid` or a - :class:`~wuttaweb.forms.base.Form` instance. - """ - labels = self.collect_labels() - for key, label in labels.items(): - obj.set_label(key, label) - - def collect_labels(self): - """ - Collect all labels defined by the view class and/or its parents. - - A master view can declare labels via class-level attribute, - like so:: - - from wuttaweb.views import MasterView - - class WidgetView(MasterView): - - labels = { - 'id': "Widget ID", - 'serial_no': "Serial Number", - } - - All such labels, defined by any class from which the master - view inherits, will be returned. However if the same label - key is defined by multiple classes, the "subclass" always - wins. - - Labels defined in this way will apply to both forms and grids. - See also :meth:`set_labels()`. - - :returns: Dict of all labels found. - """ - labels = {} - hierarchy = self.get_class_hierarchy() - for cls in hierarchy: - if hasattr(cls, 'labels'): - labels.update(cls.labels) - return labels - def make_model_grid(self, session=None, **kwargs): """ Create and return a :class:`~wuttaweb.grids.base.Grid` @@ -1137,8 +1072,6 @@ class MasterView(View): if 'uuid' in grid.columns: grid.columns.remove('uuid') - self.set_labels(grid) - for key in self.get_model_key(): grid.set_link(key) @@ -1378,8 +1311,6 @@ class MasterView(View): """ form.remove('uuid') - self.set_labels(form) - if self.editing: for key in self.get_model_key(): form.set_readonly(key) diff --git a/src/wuttaweb/views/people.py b/src/wuttaweb/views/people.py index 0ebccf6..b840a25 100644 --- a/src/wuttaweb/views/people.py +++ b/src/wuttaweb/views/people.py @@ -87,10 +87,9 @@ class PersonView(MasterView): def view_profile(self, session=None): """ """ - person = self.get_instance(session=session) + instance = self.get_instance(session=session) context = { - 'person': person, - 'instance': person, + 'instance': instance, } return self.render_to_response('view_profile', context) diff --git a/tests/forms/test_schema.py b/tests/forms/test_schema.py index ed68d3b..aef3432 100644 --- a/tests/forms/test_schema.py +++ b/tests/forms/test_schema.py @@ -22,10 +22,9 @@ class TestObjectNode(DataTestCase): model = self.app.model person = model.Person(full_name="Betty Boop") - # unsupported type is converted to string + # unsupported type raises error node = mod.ObjectNode(colander.String()) - value = node.dictify(person) - self.assertEqual(value, "Betty Boop") + self.assertRaises(NotImplementedError, node.dictify, person) # but supported type can dictify node = mod.ObjectNode(mod.PersonRef(self.request)) diff --git a/tests/grids/test_base.py b/tests/grids/test_base.py index 2d15689..c3e8f7b 100644 --- a/tests/grids/test_base.py +++ b/tests/grids/test_base.py @@ -81,30 +81,6 @@ class TestGrid(TestCase): grid.remove('two', 'three') self.assertEqual(grid.columns, ['one', 'four']) - def test_set_label(self): - grid = self.make_grid(columns=['foo', 'bar']) - self.assertEqual(grid.labels, {}) - - # basic - grid.set_label('foo', "Foo Fighters") - self.assertEqual(grid.labels['foo'], "Foo Fighters") - - # can replace label - grid.set_label('foo', "Different") - self.assertEqual(grid.labels['foo'], "Different") - self.assertEqual(grid.get_label('foo'), "Different") - - def test_get_label(self): - grid = self.make_grid(columns=['foo', 'bar']) - self.assertEqual(grid.labels, {}) - - # default derived from key - self.assertEqual(grid.get_label('foo'), "Foo") - - # can override - grid.set_label('foo', "Different") - self.assertEqual(grid.get_label('foo'), "Different") - def test_set_renderer(self): grid = self.make_grid(columns=['foo', 'bar']) self.assertEqual(grid.renderers, {}) diff --git a/tests/views/test_master.py b/tests/views/test_master.py index 8647b2a..1f00d28 100644 --- a/tests/views/test_master.py +++ b/tests/views/test_master.py @@ -10,7 +10,6 @@ from pyramid.httpexceptions import HTTPNotFound from wuttjamaican.conf import WuttaConfig from wuttaweb.views import master -from wuttaweb.views import View from wuttaweb.subscribers import new_request_set_user from tests.util import WebTestCase @@ -332,14 +331,6 @@ class TestMasterView(WebTestCase): # support methods ############################## - def test_get_class_hierarchy(self): - class MyView(master.MasterView): - pass - - view = MyView(self.request) - classes = view.get_class_hierarchy() - self.assertEqual(classes, [View, master.MasterView, MyView]) - def test_has_perm(self): model = self.app.model auth = self.app.get_auth_handler() @@ -437,36 +428,6 @@ class TestMasterView(WebTestCase): self.assertEqual(view.get_index_title(), "Wutta Widgets") del master.MasterView.model_title_plural - def test_collect_labels(self): - - # no labels by default - view = self.make_view() - labels = view.collect_labels() - self.assertEqual(labels, {}) - - # labels come from all classes; subclass wins - with patch.object(View, 'labels', new={'foo': "Foo", 'bar': "Bar"}, create=True): - with patch.object(master.MasterView, 'labels', new={'foo': "FOO FIGHTERS"}, create=True): - view = self.make_view() - labels = view.collect_labels() - self.assertEqual(labels, {'foo': "FOO FIGHTERS", 'bar': "Bar"}) - - def test_set_labels(self): - model = self.app.model - with patch.object(master.MasterView, 'model_class', new=model.Setting, create=True): - - # no labels by default - view = self.make_view() - grid = view.make_model_grid(session=self.session) - view.set_labels(grid) - self.assertEqual(grid.labels, {}) - - # labels come from all classes; subclass wins - with patch.object(master.MasterView, 'labels', new={'name': "SETTING NAME"}, create=True): - view = self.make_view() - view.set_labels(grid) - self.assertEqual(grid.labels, {'name': "SETTING NAME"}) - def test_make_model_grid(self): model = self.app.model