diff --git a/src/wuttaweb/diffs.py b/src/wuttaweb/diffs.py index ed3b237..cb59ed5 100644 --- a/src/wuttaweb/diffs.py +++ b/src/wuttaweb/diffs.py @@ -29,60 +29,20 @@ import sqlalchemy as sa from pyramid.renderers import render from webhelpers2.html import HTML +from wuttjamaican.diffs import Diff -class Diff: + +class WebDiff(Diff): """ - Represent / display a basic "diff" between two data records. + Simple diff class for the web app. - You must provide both the "old" and "new" data records, when - constructing an instance of this class. Then call - :meth:`render_html()` to display the diff table. - - :param old_data: Dict of "old" data record. - - :param new_data: Dict of "new" data record. - - :param fields: Optional list of field names. If not specified, - will be derived from the data records. - - :param nature: What sort of diff is being represented; must be one - of: ``("create", "update", "delete")`` - - :param old_color: Background color to display for "old/deleted" - field data, when applicable. - - :param new_color: Background color to display for "new/created" - field data, when applicable. + This is based on the + :class:`~wuttjamaican:wuttjamaican.diffs.Diff` class; it just + tweaks :meth:`render_html()` to use the web template lookup + engine. """ - def __init__( # pylint: disable=too-many-arguments,too-many-positional-arguments - self, - old_data: dict, - new_data: dict, - fields: list = None, - nature="update", - old_color="#ffebe9", - new_color="#dafbe1", - ): - self.old_data = old_data - self.new_data = new_data - self.columns = ["field name", "old value", "new value"] - self.fields = fields or self.make_fields() - self.nature = nature - self.old_color = old_color - self.new_color = new_color - - def make_fields(self): # pylint: disable=missing-function-docstring - return sorted(set(self.old_data) | set(self.new_data), key=lambda x: x.lower()) - - def old_value(self, field): # pylint: disable=missing-function-docstring - return self.old_data.get(field) - - def new_value(self, field): # pylint: disable=missing-function-docstring - return self.new_data.get(field) - - def values_differ(self, field): # pylint: disable=missing-function-docstring - return self.new_value(field) != self.old_value(field) + cell_padding = None def render_html(self, template="/diff.mako", **kwargs): """ @@ -98,69 +58,25 @@ class Diff: """ context = kwargs context["diff"] = self - return HTML.literal(render(template, context)) - - def render_field_row(self, field): # pylint: disable=missing-function-docstring - is_diff = self.values_differ(field) - - td_field = HTML.tag("td", class_="field", c=field) - - td_old_value = HTML.tag( - "td", - c=self.render_old_value(field), - **self.get_old_value_attrs(is_diff), - ) - - td_new_value = HTML.tag( - "td", - c=self.render_new_value(field), - **self.get_new_value_attrs(is_diff), - ) - - return HTML.tag("tr", c=[td_field, td_old_value, td_new_value]) - - def render_old_value(self, field): # pylint: disable=missing-function-docstring - value = self.old_value(field) - return repr(value) - - def render_new_value(self, field): # pylint: disable=missing-function-docstring - value = self.new_value(field) - return repr(value) - - def get_old_value_attrs( # pylint: disable=missing-function-docstring - self, is_diff - ): - attrs = {} - if self.nature == "update" and is_diff: - attrs["style"] = f"background-color: {self.old_color};" - elif self.nature == "delete": - attrs["style"] = f"background-color: {self.old_color};" - return attrs - - def get_new_value_attrs( # pylint: disable=missing-function-docstring - self, is_diff - ): - attrs = {} - if self.nature == "create": - attrs["style"] = f"background-color: {self.new_color};" - elif self.nature == "update" and is_diff: - attrs["style"] = f"background-color: {self.new_color};" - return attrs + html = render(template, context) + return HTML.literal(html) -class VersionDiff(Diff): +class VersionDiff(WebDiff): """ Special diff class for use with version history views. While - based on :class:`Diff`, this class uses a different signature for - the constructor. + based on :class:`WebDiff`, this class uses a different signature + for the constructor. - :param version: Reference to a Continuum version record (object). + :param config: The app :term:`config object`. + + :param version: Reference to a Continuum version record object. :param \\**kwargs: Remaining kwargs are passed as-is to the - :class:`Diff` constructor. + :class:`WebDiff` constructor. """ - def __init__(self, version, **kwargs): + def __init__(self, config, version, **kwargs): import sqlalchemy_continuum as continuum # pylint: disable=import-outside-toplevel from wutta_continuum.util import ( # pylint: disable=import-outside-toplevel render_operation_type, @@ -195,7 +111,7 @@ class VersionDiff(Diff): old_data[field] = getattr(version.previous, field) new_data[field] = getattr(version, field) - super().__init__(old_data, new_data, **kwargs) + super().__init__(config, old_data, new_data, **kwargs) def get_default_fields(self): # pylint: disable=missing-function-docstring fields = sorted(self.version_mapper.columns.keys()) diff --git a/src/wuttaweb/views/master.py b/src/wuttaweb/views/master.py index d5171a4..57baaff 100644 --- a/src/wuttaweb/views/master.py +++ b/src/wuttaweb/views/master.py @@ -1269,7 +1269,7 @@ class MasterView(View): # pylint: disable=too-many-public-methods ) version_diffs = [ - VersionDiff(version) + VersionDiff(self.config, version) for version in self.get_relevant_versions(txn, instance) ] diff --git a/tests/test_diffs.py b/tests/test_diffs.py index aaf17af..00c78a9 100644 --- a/tests/test_diffs.py +++ b/tests/test_diffs.py @@ -4,114 +4,10 @@ from wuttaweb import diffs as mod from wuttaweb.testing import WebTestCase, VersionWebTestCase -# nb. using WebTestCase here only for mako support in render_html() -class TestDiff(WebTestCase): +class TestWebDiff(WebTestCase): def make_diff(self, *args, **kwargs): - return mod.Diff(*args, **kwargs) - - def test_constructor(self): - old_data = {"foo": "bar"} - new_data = {"foo": "baz"} - diff = self.make_diff(old_data, new_data, fields=["foo"]) - self.assertEqual(diff.fields, ["foo"]) - - def test_make_fields(self): - old_data = {"foo": "bar"} - new_data = {"foo": "bar", "baz": "zer"} - # nb. this calls make_fields() - diff = self.make_diff(old_data, new_data) - # TODO: should the fields be cumulative? or just use new_data? - self.assertEqual(diff.fields, ["baz", "foo"]) - - def test_values(self): - old_data = {"foo": "bar"} - new_data = {"foo": "baz"} - diff = self.make_diff(old_data, new_data) - self.assertEqual(diff.old_value("foo"), "bar") - self.assertEqual(diff.new_value("foo"), "baz") - - def test_values_differ(self): - old_data = {"foo": "bar"} - new_data = {"foo": "baz"} - diff = self.make_diff(old_data, new_data) - self.assertTrue(diff.values_differ("foo")) - - old_data = {"foo": "bar"} - new_data = {"foo": "bar"} - diff = self.make_diff(old_data, new_data) - self.assertFalse(diff.values_differ("foo")) - - def test_render_values(self): - old_data = {"foo": "bar"} - new_data = {"foo": "baz"} - diff = self.make_diff(old_data, new_data) - self.assertEqual(diff.render_old_value("foo"), "'bar'") - self.assertEqual(diff.render_new_value("foo"), "'baz'") - - def test_get_old_value_attrs(self): - - # no change - old_data = {"foo": "bar"} - new_data = {"foo": "bar"} - diff = self.make_diff(old_data, new_data, nature="update") - self.assertEqual(diff.get_old_value_attrs(False), {}) - - # update - old_data = {"foo": "bar"} - new_data = {"foo": "baz"} - diff = self.make_diff(old_data, new_data, nature="update") - self.assertEqual( - diff.get_old_value_attrs(True), - {"style": f"background-color: {diff.old_color};"}, - ) - - # delete - old_data = {"foo": "bar"} - new_data = {} - diff = self.make_diff(old_data, new_data, nature="delete") - self.assertEqual( - diff.get_old_value_attrs(True), - {"style": f"background-color: {diff.old_color};"}, - ) - - def test_get_new_value_attrs(self): - - # no change - old_data = {"foo": "bar"} - new_data = {"foo": "bar"} - diff = self.make_diff(old_data, new_data, nature="update") - self.assertEqual(diff.get_new_value_attrs(False), {}) - - # update - old_data = {"foo": "bar"} - new_data = {"foo": "baz"} - diff = self.make_diff(old_data, new_data, nature="update") - self.assertEqual( - diff.get_new_value_attrs(True), - {"style": f"background-color: {diff.new_color};"}, - ) - - # create - old_data = {} - new_data = {"foo": "bar"} - diff = self.make_diff(old_data, new_data, nature="create") - self.assertEqual( - diff.get_new_value_attrs(True), - {"style": f"background-color: {diff.new_color};"}, - ) - - def test_render_field_row(self): - old_data = {"foo": "bar"} - new_data = {"foo": "baz"} - diff = self.make_diff(old_data, new_data) - row = diff.render_field_row("foo") - self.assertIn("