fix: add WebDiff class now that Diff lives in wuttjamaican
This commit is contained in:
parent
7e0b16c57d
commit
9a7488b063
3 changed files with 26 additions and 214 deletions
|
|
@ -29,60 +29,20 @@ import sqlalchemy as sa
|
||||||
from pyramid.renderers import render
|
from pyramid.renderers import render
|
||||||
from webhelpers2.html import HTML
|
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
|
This is based on the
|
||||||
constructing an instance of this class. Then call
|
:class:`~wuttjamaican:wuttjamaican.diffs.Diff` class; it just
|
||||||
:meth:`render_html()` to display the diff table.
|
tweaks :meth:`render_html()` to use the web template lookup
|
||||||
|
engine.
|
||||||
: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.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__( # pylint: disable=too-many-arguments,too-many-positional-arguments
|
cell_padding = None
|
||||||
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)
|
|
||||||
|
|
||||||
def render_html(self, template="/diff.mako", **kwargs):
|
def render_html(self, template="/diff.mako", **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -98,69 +58,25 @@ class Diff:
|
||||||
"""
|
"""
|
||||||
context = kwargs
|
context = kwargs
|
||||||
context["diff"] = self
|
context["diff"] = self
|
||||||
return HTML.literal(render(template, context))
|
html = render(template, context)
|
||||||
|
return HTML.literal(html)
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
class VersionDiff(Diff):
|
class VersionDiff(WebDiff):
|
||||||
"""
|
"""
|
||||||
Special diff class for use with version history views. While
|
Special diff class for use with version history views. While
|
||||||
based on :class:`Diff`, this class uses a different signature for
|
based on :class:`WebDiff`, this class uses a different signature
|
||||||
the constructor.
|
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
|
: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
|
import sqlalchemy_continuum as continuum # pylint: disable=import-outside-toplevel
|
||||||
from wutta_continuum.util import ( # pylint: disable=import-outside-toplevel
|
from wutta_continuum.util import ( # pylint: disable=import-outside-toplevel
|
||||||
render_operation_type,
|
render_operation_type,
|
||||||
|
|
@ -195,7 +111,7 @@ class VersionDiff(Diff):
|
||||||
old_data[field] = getattr(version.previous, field)
|
old_data[field] = getattr(version.previous, field)
|
||||||
new_data[field] = getattr(version, 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
|
def get_default_fields(self): # pylint: disable=missing-function-docstring
|
||||||
fields = sorted(self.version_mapper.columns.keys())
|
fields = sorted(self.version_mapper.columns.keys())
|
||||||
|
|
|
||||||
|
|
@ -1269,7 +1269,7 @@ class MasterView(View): # pylint: disable=too-many-public-methods
|
||||||
)
|
)
|
||||||
|
|
||||||
version_diffs = [
|
version_diffs = [
|
||||||
VersionDiff(version)
|
VersionDiff(self.config, version)
|
||||||
for version in self.get_relevant_versions(txn, instance)
|
for version in self.get_relevant_versions(txn, instance)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,114 +4,10 @@ from wuttaweb import diffs as mod
|
||||||
from wuttaweb.testing import WebTestCase, VersionWebTestCase
|
from wuttaweb.testing import WebTestCase, VersionWebTestCase
|
||||||
|
|
||||||
|
|
||||||
# nb. using WebTestCase here only for mako support in render_html()
|
class TestWebDiff(WebTestCase):
|
||||||
class TestDiff(WebTestCase):
|
|
||||||
|
|
||||||
def make_diff(self, *args, **kwargs):
|
def make_diff(self, *args, **kwargs):
|
||||||
return mod.Diff(*args, **kwargs)
|
return mod.WebDiff(self.config, *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("<tr>", row)
|
|
||||||
self.assertIn("'bar'", row)
|
|
||||||
self.assertIn(f'style="background-color: {diff.old_color};"', row)
|
|
||||||
self.assertIn("'baz'", row)
|
|
||||||
self.assertIn(f'style="background-color: {diff.new_color};"', row)
|
|
||||||
self.assertIn("</tr>", row)
|
|
||||||
|
|
||||||
def test_render_html(self):
|
def test_render_html(self):
|
||||||
old_data = {"foo": "bar"}
|
old_data = {"foo": "bar"}
|
||||||
|
|
@ -121,9 +17,9 @@ class TestDiff(WebTestCase):
|
||||||
self.assertIn("<table", html)
|
self.assertIn("<table", html)
|
||||||
self.assertIn("<tr>", html)
|
self.assertIn("<tr>", html)
|
||||||
self.assertIn("'bar'", html)
|
self.assertIn("'bar'", html)
|
||||||
self.assertIn(f'style="background-color: {diff.old_color};"', html)
|
self.assertIn(f'style="background-color: {diff.old_color}"', html)
|
||||||
self.assertIn("'baz'", html)
|
self.assertIn("'baz'", html)
|
||||||
self.assertIn(f'style="background-color: {diff.new_color};"', html)
|
self.assertIn(f'style="background-color: {diff.new_color}"', html)
|
||||||
self.assertIn("</tr>", html)
|
self.assertIn("</tr>", html)
|
||||||
self.assertIn("</table>", html)
|
self.assertIn("</table>", html)
|
||||||
|
|
||||||
|
|
@ -131,7 +27,7 @@ class TestDiff(WebTestCase):
|
||||||
class TestVersionDiff(VersionWebTestCase):
|
class TestVersionDiff(VersionWebTestCase):
|
||||||
|
|
||||||
def make_diff(self, *args, **kwargs):
|
def make_diff(self, *args, **kwargs):
|
||||||
return mod.VersionDiff(*args, **kwargs)
|
return mod.VersionDiff(self.config, *args, **kwargs)
|
||||||
|
|
||||||
def test_constructor(self):
|
def test_constructor(self):
|
||||||
import sqlalchemy_continuum as continuum
|
import sqlalchemy_continuum as continuum
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue