3
0
Fork 0

Compare commits

...

3 commits

7 changed files with 81 additions and 33 deletions

View file

@ -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/) 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). 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) ## v0.28.0 (2025-12-28)
### Feat ### Feat

View file

@ -6,7 +6,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "WuttJamaican" name = "WuttJamaican"
version = "0.28.0" version = "0.28.1"
description = "Base package for Wutta Framework" description = "Base package for Wutta Framework"
readme = "README.md" readme = "README.md"
authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}] authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}]

View file

@ -34,6 +34,7 @@ import importlib
from importlib.metadata import version from importlib.metadata import version
import humanize import humanize
from webhelpers2.html import HTML
from wuttjamaican.util import ( from wuttjamaican.util import (
get_timezone_by_name, get_timezone_by_name,
@ -915,7 +916,7 @@ class AppHandler: # pylint: disable=too-many-public-methods
return "" return ""
return value.strftime(self.display_format_date) 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. 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 :meth:`localtime()` to normalize it for display. Specify
``local=False`` to skip that and render the value as-is. ``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: if value is None:
return "" return ""
# we usually want to render a "local" time
if local: if local:
value = self.localtime(value) 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): def render_error(self, error):
""" """

View file

@ -282,6 +282,10 @@ class UserRole(Base): # pylint: disable=too-few-public-methods
__tablename__ = "user_x_role" __tablename__ = "user_x_role"
__versioned__ = {} __versioned__ = {}
__wutta_hint__ = {
"model_title": "User Role",
"model_title_plural": "User Roles",
}
uuid = uuid_column() uuid = uuid_column()
@ -312,6 +316,10 @@ class UserAPIToken(Base): # pylint: disable=too-few-public-methods
""" """
__tablename__ = "user_api_token" __tablename__ = "user_api_token"
__wutta_hint__ = {
"model_title": "User API Token",
"model_title_plural": "User API Tokens",
}
uuid = uuid_column() uuid = uuid_column()

View file

@ -166,6 +166,10 @@ class Person(Base):
__tablename__ = "person" __tablename__ = "person"
__versioned__ = {} __versioned__ = {}
__wutta_hint__ = {
"model_title": "Person",
"model_title_plural": "People",
}
uuid = uuid_column() uuid = uuid_column()

View file

@ -105,9 +105,9 @@ class FileTestCase(TestCase):
f.write(content) f.write(content)
return path return path
def mkdir( # pragma: no cover; pylint: disable=unused-argument,empty-docstring def mkdir(
self, dirname self, dirname
): ): # pragma: no cover; pylint: disable=unused-argument,empty-docstring
""" """ """ """
warnings.warn( warnings.warn(
"FileTestCase.mkdir() is deprecated; " "FileTestCase.mkdir() is deprecated; "

View file

@ -595,38 +595,42 @@ app_title = WuttaTest
self.assertEqual(self.app.render_date(dt), "2024-12-11") self.assertEqual(self.app.render_date(dt), "2024-12-11")
def test_render_datetime(self): def test_render_datetime(self):
self.config.setdefault("wuttatest.timezone.default", "America/Los_Angeles")
tzlocal = get_timezone_by_name("America/Los_Angeles") tzlocal = get_timezone_by_name("America/Los_Angeles")
with patch.object(self.app, "get_timezone", return_value=tzlocal):
# null value # null value
self.assertEqual(self.app.render_datetime(None), "") self.assertEqual(self.app.render_datetime(None), "")
# naive UTC # naive UTC
dt = datetime.datetime(2024, 12, 17, 1, 12) dt = datetime.datetime(2024, 12, 17, 1, 12)
self.assertEqual( self.assertEqual(
self.app.render_datetime(dt, local=True), "2024-12-16 17:12-0800" self.app.render_datetime(dt, local=True), "2024-12-16 17:12-0800"
) )
self.assertEqual( self.assertEqual(self.app.render_datetime(dt, local=False), "2024-12-17 01:12")
self.app.render_datetime(dt, local=False), "2024-12-17 01:12"
)
# aware UTC # aware UTC
dt = datetime.datetime(2024, 12, 17, 1, 12, tzinfo=datetime.timezone.utc) dt = datetime.datetime(2024, 12, 17, 1, 12, tzinfo=datetime.timezone.utc)
self.assertEqual( self.assertEqual(
self.app.render_datetime(dt, local=True), "2024-12-16 17:12-0800" self.app.render_datetime(dt, local=True), "2024-12-16 17:12-0800"
) )
self.assertEqual( self.assertEqual(
self.app.render_datetime(dt, local=False), "2024-12-17 01:12+0000" self.app.render_datetime(dt, local=False), "2024-12-17 01:12+0000"
) )
# aware local # aware local
dt = datetime.datetime(2024, 12, 16, 19, 12, tzinfo=tzlocal) dt = datetime.datetime(2024, 12, 16, 19, 12, tzinfo=tzlocal)
self.assertEqual( self.assertEqual(
self.app.render_datetime(dt, local=True), "2024-12-16 19:12-0800" self.app.render_datetime(dt, local=True), "2024-12-16 19:12-0800"
) )
self.assertEqual( self.assertEqual(
self.app.render_datetime(dt, local=False), "2024-12-16 19:12-0800" 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('<span title="'))
self.assertIn("2024-12-16 19:12-0800", html)
def test_render_error(self): def test_render_error(self):