From ab0a6e72fe6877291c917539f94e2bb26b7a5084 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Mon, 29 Dec 2025 14:07:40 -0600 Subject: [PATCH 1/3] fix: add `html` flag param for `app.render_datetime()` --- src/wuttjamaican/app.py | 27 +++++++++++++++-- src/wuttjamaican/testing.py | 4 +-- tests/test_app.py | 58 ++++++++++++++++++++----------------- 3 files changed, 57 insertions(+), 32 deletions(-) diff --git a/src/wuttjamaican/app.py b/src/wuttjamaican/app.py index 9f4f41b..a623af8 100644 --- a/src/wuttjamaican/app.py +++ b/src/wuttjamaican/app.py @@ -34,6 +34,7 @@ import importlib from importlib.metadata import version import humanize +from webhelpers2.html import HTML from wuttjamaican.util import ( get_timezone_by_name, @@ -915,7 +916,7 @@ class AppHandler: # pylint: disable=too-many-public-methods return "" return value.strftime(self.display_format_date) - def render_datetime(self, value, local=True): + def render_datetime(self, value, local=True, html=False): """ Return a human-friendly display string for the given datetime. @@ -928,13 +929,33 @@ class AppHandler: # pylint: disable=too-many-public-methods :meth:`localtime()` to normalize it for display. Specify ``local=False`` to skip that and render the value as-is. - :returns: Rendered datetime as string. + :param html: If true, return HTML (with tooltip showing + relative time delta) instead of plain text. + + :returns: Rendered datetime as string (or HTML with tooltip). """ if value is None: return "" + + # we usually want to render a "local" time if local: value = self.localtime(value) - return value.strftime(self.display_format_datetime) + + # simple formatted text + text = value.strftime(self.display_format_datetime) + + if html: + + # calculate time diff + # nb. if both times are naive, they should be UTC; + # otherwise if both are zone-aware, this should work even + # if they use different zones. + delta = self.make_utc(tzinfo=bool(value.tzinfo)) - value + + # show text w/ time diff as tooltip + return HTML.tag("span", c=text, title=self.render_time_ago(delta)) + + return text def render_error(self, error): """ diff --git a/src/wuttjamaican/testing.py b/src/wuttjamaican/testing.py index 76a1da0..59db454 100644 --- a/src/wuttjamaican/testing.py +++ b/src/wuttjamaican/testing.py @@ -105,9 +105,9 @@ class FileTestCase(TestCase): f.write(content) return path - def mkdir( # pragma: no cover; pylint: disable=unused-argument,empty-docstring + def mkdir( self, dirname - ): + ): # pragma: no cover; pylint: disable=unused-argument,empty-docstring """ """ warnings.warn( "FileTestCase.mkdir() is deprecated; " diff --git a/tests/test_app.py b/tests/test_app.py index bf51576..3693b2d 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -595,38 +595,42 @@ app_title = WuttaTest self.assertEqual(self.app.render_date(dt), "2024-12-11") def test_render_datetime(self): + self.config.setdefault("wuttatest.timezone.default", "America/Los_Angeles") tzlocal = get_timezone_by_name("America/Los_Angeles") - with patch.object(self.app, "get_timezone", return_value=tzlocal): - # null value - self.assertEqual(self.app.render_datetime(None), "") + # null value + self.assertEqual(self.app.render_datetime(None), "") - # naive UTC - dt = datetime.datetime(2024, 12, 17, 1, 12) - self.assertEqual( - self.app.render_datetime(dt, local=True), "2024-12-16 17:12-0800" - ) - self.assertEqual( - self.app.render_datetime(dt, local=False), "2024-12-17 01:12" - ) + # naive UTC + dt = datetime.datetime(2024, 12, 17, 1, 12) + self.assertEqual( + self.app.render_datetime(dt, local=True), "2024-12-16 17:12-0800" + ) + self.assertEqual(self.app.render_datetime(dt, local=False), "2024-12-17 01:12") - # aware UTC - dt = datetime.datetime(2024, 12, 17, 1, 12, tzinfo=datetime.timezone.utc) - self.assertEqual( - self.app.render_datetime(dt, local=True), "2024-12-16 17:12-0800" - ) - self.assertEqual( - self.app.render_datetime(dt, local=False), "2024-12-17 01:12+0000" - ) + # aware UTC + dt = datetime.datetime(2024, 12, 17, 1, 12, tzinfo=datetime.timezone.utc) + self.assertEqual( + self.app.render_datetime(dt, local=True), "2024-12-16 17:12-0800" + ) + self.assertEqual( + self.app.render_datetime(dt, local=False), "2024-12-17 01:12+0000" + ) - # aware local - dt = datetime.datetime(2024, 12, 16, 19, 12, tzinfo=tzlocal) - self.assertEqual( - self.app.render_datetime(dt, local=True), "2024-12-16 19:12-0800" - ) - self.assertEqual( - self.app.render_datetime(dt, local=False), "2024-12-16 19:12-0800" - ) + # aware local + dt = datetime.datetime(2024, 12, 16, 19, 12, tzinfo=tzlocal) + self.assertEqual( + self.app.render_datetime(dt, local=True), "2024-12-16 19:12-0800" + ) + self.assertEqual( + self.app.render_datetime(dt, local=False), "2024-12-16 19:12-0800" + ) + + # as html + dt = datetime.datetime(2024, 12, 16, 19, 12, tzinfo=tzlocal) + html = self.app.render_datetime(dt, local=True, html=True) + self.assertTrue(html.startswith(' Date: Wed, 31 Dec 2025 18:55:27 -0600 Subject: [PATCH 2/3] fix: add model title hints to core models --- src/wuttjamaican/db/model/auth.py | 8 ++++++++ src/wuttjamaican/db/model/base.py | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/src/wuttjamaican/db/model/auth.py b/src/wuttjamaican/db/model/auth.py index 2a48369..59fc900 100644 --- a/src/wuttjamaican/db/model/auth.py +++ b/src/wuttjamaican/db/model/auth.py @@ -282,6 +282,10 @@ class UserRole(Base): # pylint: disable=too-few-public-methods __tablename__ = "user_x_role" __versioned__ = {} + __wutta_hint__ = { + "model_title": "User Role", + "model_title_plural": "User Roles", + } uuid = uuid_column() @@ -312,6 +316,10 @@ class UserAPIToken(Base): # pylint: disable=too-few-public-methods """ __tablename__ = "user_api_token" + __wutta_hint__ = { + "model_title": "User API Token", + "model_title_plural": "User API Tokens", + } uuid = uuid_column() diff --git a/src/wuttjamaican/db/model/base.py b/src/wuttjamaican/db/model/base.py index db2a2a1..e66e6d9 100644 --- a/src/wuttjamaican/db/model/base.py +++ b/src/wuttjamaican/db/model/base.py @@ -166,6 +166,10 @@ class Person(Base): __tablename__ = "person" __versioned__ = {} + __wutta_hint__ = { + "model_title": "Person", + "model_title_plural": "People", + } uuid = uuid_column() From 2713ad72e5c2f3260b349c73f1ff66183547a786 Mon Sep 17 00:00:00 2001 From: Lance Edgar Date: Wed, 31 Dec 2025 19:09:47 -0600 Subject: [PATCH 3/3] =?UTF-8?q?bump:=20version=200.28.0=20=E2=86=92=200.28?= =?UTF-8?q?.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 11 +++++++++++ pyproject.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 974176f..4483972 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to WuttJamaican 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.28.1 (2025-12-31) + +### Fix + +- add model title hints to core models +- add `html` flag param for `app.render_datetime()` +- tweak subcommand docstring, to match others/convention +- add `--comment` param for wutta typer commands +- auto-add doc string for uuid primary key columns +- add `--runas` param for wutta typer commands + ## v0.28.0 (2025-12-28) ### Feat diff --git a/pyproject.toml b/pyproject.toml index bd0d5df..a8c75f8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "WuttJamaican" -version = "0.28.0" +version = "0.28.1" description = "Base package for Wutta Framework" readme = "README.md" authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]