diff --git a/CHANGELOG.md b/CHANGELOG.md index 1897120..8d4a089 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,15 +5,6 @@ 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.7 (2026-02-17) - -### Fix - -- add assocation proxies for `User.first_name` and `User.last_name` -- add `get_value()` convenience function -- comment out app_title in default wutta.conf for installer -- add `app.today()` convenience method - ## v0.28.6 (2026-01-04) ### Fix diff --git a/pyproject.toml b/pyproject.toml index 1cd82a5..1c3f165 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "WuttJamaican" -version = "0.28.7" +version = "0.28.6" description = "Base package for Wutta Framework" readme = "README.md" authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}] diff --git a/src/wuttjamaican/app.py b/src/wuttjamaican/app.py index 6314f9d..d8483b4 100644 --- a/src/wuttjamaican/app.py +++ b/src/wuttjamaican/app.py @@ -38,7 +38,6 @@ from webhelpers2.html import HTML from wuttjamaican.util import ( get_timezone_by_name, - get_value, localtime, load_entry_points, load_object, @@ -375,22 +374,6 @@ class AppHandler: # pylint: disable=too-many-public-methods self.__dict__["enum"] = importlib.import_module(spec) return self.enum - def get_value(self, obj, key): - """ - Convenience wrapper around - :func:`wuttjamaican.util.get_value()`. - - :param obj: Arbitrary dict or object of any kind which would - have named attributes. - - :param key: Key/name of the field to get. - - :returns: Whatever value is found. Or maybe an - ``AttributeError`` is raised if the object does not have - the key/attr set. - """ - return get_value(obj, key) - def load_object(self, spec): """ Import and/or load and return the object designated by the diff --git a/src/wuttjamaican/db/model/auth.py b/src/wuttjamaican/db/model/auth.py index 9a5ab3b..59fc900 100644 --- a/src/wuttjamaican/db/model/auth.py +++ b/src/wuttjamaican/db/model/auth.py @@ -44,7 +44,7 @@ from sqlalchemy import orm from sqlalchemy.ext.associationproxy import association_proxy from wuttjamaican.db.util import uuid_column, uuid_fk_column -from wuttjamaican.db.model.base import Base, Person +from wuttjamaican.db.model.base import Base from wuttjamaican.util import make_utc @@ -204,6 +204,8 @@ class User(Base): # pylint: disable=too-few-public-methods person_uuid = uuid_fk_column("person.uuid", nullable=True) person = orm.relationship( "Person", + # TODO: seems like this is not needed? + # uselist=False, back_populates="users", cascade_backrefs=False, doc=""" @@ -212,21 +214,6 @@ class User(Base): # pylint: disable=too-few-public-methods """, ) - # TODO: these may or may not be good ideas? i added them mostly - # for sake of testing association proxy behavior in wuttaweb, b/c - # i was lazy and didn't want to write proper fixtures. so if - # they are a problem then doing that should fix it.. - first_name = association_proxy( - "person", - "first_name", - creator=lambda n: Person(first_name=n, full_name=n), - ) - last_name = association_proxy( - "person", - "last_name", - creator=lambda n: Person(last_name=n, full_name=n), - ) - active = sa.Column( sa.Boolean(), nullable=False, diff --git a/src/wuttjamaican/db/util.py b/src/wuttjamaican/db/util.py index d01917d..da4720f 100644 --- a/src/wuttjamaican/db/util.py +++ b/src/wuttjamaican/db/util.py @@ -56,8 +56,6 @@ class ModelBase: # pylint: disable=empty-docstring def __iter__(self): # nb. we override this to allow for `dict(self)` - # nb. this does *not* include association proxy values; - # see also wuttjamaican.util.get_value() state = sa.inspect(self) fields = [attr.key for attr in state.attrs] return iter([(field, getattr(self, field)) for field in fields]) diff --git a/src/wuttjamaican/util.py b/src/wuttjamaican/util.py index b1ef966..a129887 100644 --- a/src/wuttjamaican/util.py +++ b/src/wuttjamaican/util.py @@ -82,34 +82,6 @@ def get_class_hierarchy(klass, topfirst=True): return hierarchy -def get_value(obj, key): - """ - Convenience function to retrive a value by name from the given - object. This will first try to assume the object is a dict but - will fallback to using ``getattr()`` on it. - - :param obj: Arbitrary dict or object of any kind which would have - named attributes. - - :param key: Key/name of the field to get. - - :returns: Whatever value is found. Or maybe an ``AttributeError`` - is raised if the object does not have the key/attr set. - """ - # nb. we try dict access first, since wutta data model objects - # should all support that anyway, so it's 2 birds 1 stone. - try: - return obj[key] - - except (KeyError, TypeError): - # nb. key error means the object supports key lookup (i.e. is - # dict-like) but did not have that key set. which is actually - # an expected scenario for association proxy fields, but for - # those a getattr() should still work; see also - # wuttjamaican.db.util.ModelBase - return getattr(obj, key) - - def load_entry_points(group, ignore_errors=False): """ Load a set of ``setuptools``-style entry points. diff --git a/tests/test_app.py b/tests/test_app.py index 78a8862..1070e28 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -48,32 +48,6 @@ class TestAppHandler(FileTestCase): def test_get_enum(self): self.assertIs(self.app.get_enum(), wuttjamaican.enum) - def test_get_value(self): - - class Object: - def __init__(self, **kw): - self.__dict__.update(kw) - - class Dict(dict): - pass - - # dict object - obj = {"foo": "bar"} - self.assertEqual(self.app.get_value(obj, "foo"), "bar") - - # object w/ attrs - obj = Object(foo="bar") - self.assertEqual(self.app.get_value(obj, "foo"), "bar") - - # dict-like w/ attrs - obj = Dict({"foo": "bar"}) - obj.baz = "yyy" - self.assertEqual(self.app.get_value(obj, "baz"), "yyy") - - # missing attr - obj = Object(foo="bar") - self.assertRaises(AttributeError, self.app.get_value, obj, "baz") - def test_load_object(self): # just confirm the method works on a basic level; the diff --git a/tests/test_util.py b/tests/test_util.py index ddf220e..31b0527 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -41,35 +41,6 @@ class TestGetClassHierarchy(TestCase): self.assertEqual(classes, [C, B, A]) -class TestGetValue(TestCase): - - def test_basic(self): - - class Object: - def __init__(self, **kw): - self.__dict__.update(kw) - - class Dict(dict): - pass - - # dict object - obj = {"foo": "bar"} - self.assertEqual(mod.get_value(obj, "foo"), "bar") - - # object w/ attrs - obj = Object(foo="bar") - self.assertEqual(mod.get_value(obj, "foo"), "bar") - - # dict-like w/ attrs - obj = Dict({"foo": "bar"}) - obj.baz = "yyy" - self.assertEqual(mod.get_value(obj, "baz"), "yyy") - - # missing attr - obj = Object(foo="bar") - self.assertRaises(AttributeError, mod.get_value, obj, "baz") - - class TestLoadEntryPoints(TestCase): def test_empty(self):