diff --git a/CHANGELOG.md b/CHANGELOG.md index ee32008..8c4f50d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ 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.16.1 (2024-12-05) + +### Fix + +- add `db.util.make_topo_sortkey()` function +- use true UUID type for Upgrades table primary key +- let caller set data type for `uuid_column()` and `uuid_fk_column()` +- avoid error when loading installer templates + ## v0.16.0 (2024-11-30) ### Feat diff --git a/docs/narr/install/quickstart.rst b/docs/narr/install/quickstart.rst index 0fea804..84a491d 100644 --- a/docs/narr/install/quickstart.rst +++ b/docs/narr/install/quickstart.rst @@ -22,35 +22,39 @@ Make a parent folder for all source code: mkdir -p ~/src -Make a :term:`virtual environment` for your project: +Make and activate a new :term:`virtual environment` for your project: .. code-block:: sh cd /path/to/envs python3 -m venv poser + source poser/bin/activate Make a new e.g. ``poser`` database in PostgreSQL (or MySQL). -Install and run cookiecutter with wuttaweb template: +Install and run `cookiecutter `_ +with `wuttaweb template +`_: .. code-block:: sh - cd /path/to/envs/poser - bin/pip install cookiecutter - bin/cookiecutter -o ~/src git+https://forgejo.wuttaproject.org/wutta/cookiecutter-wuttaweb + pip install cookiecutter + cookiecutter -o ~/src git+https://forgejo.wuttaproject.org/wutta/cookiecutter-wuttaweb Assuming you now have project code at ``~/src/poser`` then install -that and run the app installer: +that and run the app installer. Note the 2nd command name will depend +on your project: .. code-block:: sh - bin/pip install -e ~/src/poser - bin/poser install + pip install -e ~/src/poser + poser install If all goes well, you can run the web app with: .. code-block:: sh + cd /path/to/envs/poser bin/pserve --reload file+ini:app/web.conf And browse it at http://localhost:9080 diff --git a/pyproject.toml b/pyproject.toml index 96ce552..d9c0ce8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,10 +6,10 @@ build-backend = "hatchling.build" [project] name = "WuttJamaican" -version = "0.16.0" +version = "0.16.1" description = "Base package for Wutta Framework" readme = "README.md" -authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] +authors = [{name = "Lance Edgar", email = "lance@wuttaproject.org"}] license = {text = "GNU GPL v3+"} classifiers = [ "Development Status :: 4 - Beta", @@ -49,6 +49,7 @@ wutta = "wuttjamaican.cli:wutta_typer" [project.urls] Homepage = "https://wuttaproject.org/" Repository = "https://forgejo.wuttaproject.org/wutta/wuttjamaican" +Issues = "https://forgejo.wuttaproject.org/wutta/wuttjamaican/issues" Changelog = "https://forgejo.wuttaproject.org/wutta/wuttjamaican/src/branch/master/CHANGELOG.md" diff --git a/src/wuttjamaican/db/util.py b/src/wuttjamaican/db/util.py index 0df0e68..643e267 100644 --- a/src/wuttjamaican/db/util.py +++ b/src/wuttjamaican/db/util.py @@ -27,6 +27,7 @@ Database Utilities import uuid as _uuid import sqlalchemy as sa +from sqlalchemy import orm from sqlalchemy.dialects.postgresql import UUID as PGUUID from wuttjamaican.util import make_uuid @@ -127,3 +128,26 @@ def uuid_fk_column(target_column, *args, **kwargs): if not args: args = (sa.String(length=32), sa.ForeignKey(target_column)) return sa.Column(*args, **kwargs) + + +def make_topo_sortkey(model): + """ + Returns a function suitable for use as a ``key`` kwarg to a + standard Python sorting call. This key function will expect a + single class mapper and return a sequence number associated with + that model. The sequence is determined by SQLAlchemy's + topological table sorting. + + :param model: Usually the :term:`app model`, but can be any module + containing model classes. + """ + metadata = model.Base.metadata + tables = dict([(table.name, i) + for i, table in enumerate(metadata.sorted_tables, 1)]) + + def sortkey(name): + cls = getattr(model, name) + mapper = orm.class_mapper(cls) + return tuple(tables[t.name] for t in mapper.tables) + + return sortkey diff --git a/tests/db/test_util.py b/tests/db/test_util.py index 2f0c9ed..8ffef76 100644 --- a/tests/db/test_util.py +++ b/tests/db/test_util.py @@ -11,6 +11,7 @@ try: from wuttjamaican.db import util as mod from wuttjamaican.db.model.base import Setting from wuttjamaican.util import make_true_uuid + from wuttjamaican.testing import DataTestCase except ImportError: pass else: @@ -124,3 +125,17 @@ else: self.assertIsInstance(column, sa.Column) self.assertIsInstance(column.type, sa.String) self.assertEqual(column.type.length, 32) + + + class TestMakeTopoSortkey(DataTestCase): + + def test_basic(self): + model = self.app.model + sortkey = mod.make_topo_sortkey(model) + original = ['User', 'Person', 'UserRole', 'Role'] + + # models are sorted so dependants come later + result = sorted(original, key=sortkey) + self.assertTrue(result.index('Role') < result.index('UserRole')) + self.assertTrue(result.index('User') < result.index('UserRole')) + self.assertTrue(result.index('Person') < result.index('User'))