Compare commits
3 commits
7ebaaa1d91
...
2713ad72e5
| Author | SHA1 | Date | |
|---|---|---|---|
| 2713ad72e5 | |||
| 8d43c294d0 | |||
| ab0a6e72fe |
7 changed files with 81 additions and 33 deletions
11
CHANGELOG.md
11
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/)
|
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
|
||||||
|
|
|
||||||
|
|
@ -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"}]
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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; "
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue