Compare commits
	
		
			No commits in common. "cb147c203db200136010cd1d96b027fa48ea3d97" and "e9507fb5a468a66f44fa0564dc5329aa299096cc" have entirely different histories.
		
	
	
		
			cb147c203d
			...
			e9507fb5a4
		
	
		
					 9 changed files with 83 additions and 141 deletions
				
			
		|  | @ -5,12 +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.13.3 (2024-08-30) | ||||
| 
 | ||||
| ### Fix | ||||
| 
 | ||||
| - move model base class out of model subpkg | ||||
| 
 | ||||
| ## v0.13.2 (2024-08-27) | ||||
| 
 | ||||
| ### Fix | ||||
|  |  | |||
|  | @ -1,6 +0,0 @@ | |||
| 
 | ||||
| ``wuttjamaican.db.util`` | ||||
| ======================== | ||||
| 
 | ||||
| .. automodule:: wuttjamaican.db.util | ||||
|    :members: | ||||
|  | @ -17,7 +17,6 @@ | |||
|    db.model.base | ||||
|    db.model.upgrades | ||||
|    db.sess | ||||
|    db.util | ||||
|    email | ||||
|    email.handler | ||||
|    email.message | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ build-backend = "hatchling.build" | |||
| 
 | ||||
| [project] | ||||
| name = "WuttJamaican" | ||||
| version = "0.13.3" | ||||
| version = "0.13.2" | ||||
| description = "Base package for Wutta Framework" | ||||
| readme = "README.md" | ||||
| authors = [{name = "Lance Edgar", email = "lance@edbob.org"}] | ||||
|  |  | |||
|  | @ -27,6 +27,8 @@ This is the default :term:`app model` module. | |||
| 
 | ||||
| The ``wuttjamaican.db.model`` namespace contains the following: | ||||
| 
 | ||||
| * :func:`~wuttjamaican.db.model.base.uuid_column()` | ||||
| * :func:`~wuttjamaican.db.model.base.uuid_fk_column()` | ||||
| * :class:`~wuttjamaican.db.model.base.Base` | ||||
| * :class:`~wuttjamaican.db.model.base.Setting` | ||||
| * :class:`~wuttjamaican.db.model.base.Person` | ||||
|  | @ -37,9 +39,6 @@ The ``wuttjamaican.db.model`` namespace contains the following: | |||
| * :class:`~wuttjamaican.db.model.upgrades.Upgrade` | ||||
| """ | ||||
| 
 | ||||
| # TODO: remove these | ||||
| from wuttjamaican.db.util import uuid_column, uuid_fk_column | ||||
| 
 | ||||
| from .base import Base, Setting, Person | ||||
| from .base import uuid_column, uuid_fk_column, Base, Setting, Person | ||||
| from .auth import Role, Permission, User, UserRole | ||||
| from .upgrades import Upgrade | ||||
|  |  | |||
|  | @ -31,15 +31,62 @@ Base Models | |||
| import sqlalchemy as sa | ||||
| from sqlalchemy import orm | ||||
| 
 | ||||
| from wuttjamaican.db.util import (naming_convention, ModelBase, | ||||
|                                   uuid_column, uuid_fk_column) | ||||
| from wuttjamaican.util import make_uuid | ||||
| 
 | ||||
| 
 | ||||
| # nb. this convention comes from upstream docs | ||||
| # https://docs.sqlalchemy.org/en/14/core/constraints.html#constraint-naming-conventions | ||||
| naming_convention = { | ||||
|     'ix': 'ix_%(column_0_label)s', | ||||
|     'uq': 'uq_%(table_name)s_%(column_0_name)s', | ||||
|     'ck': 'ck_%(table_name)s_%(constraint_name)s', | ||||
|     'fk': 'fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s', | ||||
|     'pk': 'pk_%(table_name)s', | ||||
| } | ||||
| 
 | ||||
| metadata = sa.MetaData(naming_convention=naming_convention) | ||||
| 
 | ||||
| 
 | ||||
| class ModelBase: | ||||
|     """ """ | ||||
| 
 | ||||
|     def __iter__(self): | ||||
|         # nb. we override this to allow for `dict(self)` | ||||
|         state = sa.inspect(self) | ||||
|         fields = [attr.key for attr in state.attrs] | ||||
|         return iter([(field, getattr(self, field)) | ||||
|                      for field in fields]) | ||||
| 
 | ||||
|     def __getitem__(self, key): | ||||
|         # nb. we override this to allow for `x = self['field']` | ||||
|         state = sa.inspect(self) | ||||
|         if hasattr(state.attrs, key): | ||||
|             return getattr(self, key) | ||||
| 
 | ||||
| 
 | ||||
| Base = orm.declarative_base(metadata=metadata, cls=ModelBase) | ||||
| 
 | ||||
| 
 | ||||
| def uuid_column(*args, **kwargs): | ||||
|     """ | ||||
|     Returns a UUID column for use as a table's primary key. | ||||
|     """ | ||||
|     kwargs.setdefault('primary_key', True) | ||||
|     kwargs.setdefault('nullable', False) | ||||
|     kwargs.setdefault('default', make_uuid) | ||||
|     return sa.Column(sa.String(length=32), *args, **kwargs) | ||||
| 
 | ||||
| 
 | ||||
| def uuid_fk_column(target_column, *args, **kwargs): | ||||
|     """ | ||||
|     Returns a UUID column for use as a foreign key to another table. | ||||
| 
 | ||||
|     :param target_column: Name of the table column on the remote side, | ||||
|        e.g. ``'user.uuid'``. | ||||
|     """ | ||||
|     return sa.Column(sa.String(length=32), sa.ForeignKey(target_column), *args, **kwargs) | ||||
| 
 | ||||
| 
 | ||||
| class Setting(Base): | ||||
|     """ | ||||
|     Represents a :term:`config setting`. | ||||
|  |  | |||
|  | @ -1,77 +0,0 @@ | |||
| # -*- coding: utf-8; -*- | ||||
| ################################################################################ | ||||
| # | ||||
| #  WuttJamaican -- Base package for Wutta Framework | ||||
| #  Copyright © 2023-2024 Lance Edgar | ||||
| # | ||||
| #  This file is part of Wutta Framework. | ||||
| # | ||||
| #  Wutta Framework is free software: you can redistribute it and/or modify it | ||||
| #  under the terms of the GNU General Public License as published by the Free | ||||
| #  Software Foundation, either version 3 of the License, or (at your option) any | ||||
| #  later version. | ||||
| # | ||||
| #  Wutta Framework is distributed in the hope that it will be useful, but | ||||
| #  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||||
| #  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for | ||||
| #  more details. | ||||
| # | ||||
| #  You should have received a copy of the GNU General Public License along with | ||||
| #  Wutta Framework.  If not, see <http://www.gnu.org/licenses/>. | ||||
| # | ||||
| ################################################################################ | ||||
| """ | ||||
| Database Utilities | ||||
| """ | ||||
| 
 | ||||
| import sqlalchemy as sa | ||||
| 
 | ||||
| from wuttjamaican.util import make_uuid | ||||
| 
 | ||||
| 
 | ||||
| # nb. this convention comes from upstream docs | ||||
| # https://docs.sqlalchemy.org/en/14/core/constraints.html#constraint-naming-conventions | ||||
| naming_convention = { | ||||
|     'ix': 'ix_%(column_0_label)s', | ||||
|     'uq': 'uq_%(table_name)s_%(column_0_name)s', | ||||
|     'ck': 'ck_%(table_name)s_%(constraint_name)s', | ||||
|     'fk': 'fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s', | ||||
|     'pk': 'pk_%(table_name)s', | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class ModelBase: | ||||
|     """ """ | ||||
| 
 | ||||
|     def __iter__(self): | ||||
|         # nb. we override this to allow for `dict(self)` | ||||
|         state = sa.inspect(self) | ||||
|         fields = [attr.key for attr in state.attrs] | ||||
|         return iter([(field, getattr(self, field)) | ||||
|                      for field in fields]) | ||||
| 
 | ||||
|     def __getitem__(self, key): | ||||
|         # nb. we override this to allow for `x = self['field']` | ||||
|         state = sa.inspect(self) | ||||
|         if hasattr(state.attrs, key): | ||||
|             return getattr(self, key) | ||||
| 
 | ||||
| 
 | ||||
| def uuid_column(*args, **kwargs): | ||||
|     """ | ||||
|     Returns a UUID column for use as a table's primary key. | ||||
|     """ | ||||
|     kwargs.setdefault('primary_key', True) | ||||
|     kwargs.setdefault('nullable', False) | ||||
|     kwargs.setdefault('default', make_uuid) | ||||
|     return sa.Column(sa.String(length=32), *args, **kwargs) | ||||
| 
 | ||||
| 
 | ||||
| def uuid_fk_column(target_column, *args, **kwargs): | ||||
|     """ | ||||
|     Returns a UUID column for use as a foreign key to another table. | ||||
| 
 | ||||
|     :param target_column: Name of the table column on the remote side, | ||||
|        e.g. ``'user.uuid'``. | ||||
|     """ | ||||
|     return sa.Column(sa.String(length=32), sa.ForeignKey(target_column), *args, **kwargs) | ||||
|  | @ -3,16 +3,42 @@ | |||
| from unittest import TestCase | ||||
| 
 | ||||
| try: | ||||
|     from wuttjamaican.db.model import base as mod | ||||
|     import sqlalchemy as sa | ||||
|     from wuttjamaican.db.model import base as model | ||||
|     from wuttjamaican.db.model.auth import User | ||||
| except ImportError: | ||||
|     pass | ||||
| else: | ||||
| 
 | ||||
|     class TestModelBase(TestCase): | ||||
| 
 | ||||
|         def test_dict_behavior(self): | ||||
|             setting = model.Setting() | ||||
|             self.assertEqual(list(iter(setting)), [('name', None), ('value', None)]) | ||||
|             self.assertIsNone(setting['name']) | ||||
|             setting.name = 'foo' | ||||
|             self.assertEqual(setting['name'], 'foo') | ||||
| 
 | ||||
|     class TestUUIDColumn(TestCase): | ||||
| 
 | ||||
|         def test_basic(self): | ||||
|             column = model.uuid_column() | ||||
|             self.assertIsInstance(column, sa.Column) | ||||
|             self.assertIsInstance(column.type, sa.String) | ||||
|             self.assertEqual(column.type.length, 32) | ||||
| 
 | ||||
|     class TestUUIDFKColumn(TestCase): | ||||
| 
 | ||||
|         def test_basic(self): | ||||
|             column = model.uuid_fk_column('foo.bar') | ||||
|             self.assertIsInstance(column, sa.Column) | ||||
|             self.assertIsInstance(column.type, sa.String) | ||||
|             self.assertEqual(column.type.length, 32) | ||||
| 
 | ||||
|     class TestSetting(TestCase): | ||||
| 
 | ||||
|         def test_basic(self): | ||||
|             setting = mod.Setting() | ||||
|             setting = model.Setting() | ||||
|             self.assertEqual(str(setting), "") | ||||
|             setting.name = 'foo' | ||||
|             self.assertEqual(str(setting), "foo") | ||||
|  | @ -20,13 +46,13 @@ else: | |||
|     class TestPerson(TestCase): | ||||
| 
 | ||||
|         def test_basic(self): | ||||
|             person = mod.Person() | ||||
|             person = model.Person() | ||||
|             self.assertEqual(str(person), "") | ||||
|             person.full_name = "Barney Rubble" | ||||
|             self.assertEqual(str(person), "Barney Rubble") | ||||
| 
 | ||||
|         def test_users(self): | ||||
|             person = mod.Person() | ||||
|             person = model.Person() | ||||
|             self.assertIsNone(person.user) | ||||
| 
 | ||||
|             user = User() | ||||
|  |  | |||
|  | @ -1,40 +0,0 @@ | |||
| # -*- coding: utf-8; -*- | ||||
| 
 | ||||
| from unittest import TestCase | ||||
| 
 | ||||
| 
 | ||||
| try: | ||||
|     import sqlalchemy as sa | ||||
|     from wuttjamaican.db import util as mod | ||||
|     from wuttjamaican.db.model.base import Setting | ||||
| except ImportError: | ||||
|     pass | ||||
| else: | ||||
| 
 | ||||
| 
 | ||||
|     class TestModelBase(TestCase): | ||||
| 
 | ||||
|         def test_dict_behavior(self): | ||||
|             setting = Setting() | ||||
|             self.assertEqual(list(iter(setting)), [('name', None), ('value', None)]) | ||||
|             self.assertIsNone(setting['name']) | ||||
|             setting.name = 'foo' | ||||
|             self.assertEqual(setting['name'], 'foo') | ||||
| 
 | ||||
| 
 | ||||
|     class TestUUIDColumn(TestCase): | ||||
| 
 | ||||
|         def test_basic(self): | ||||
|             column = mod.uuid_column() | ||||
|             self.assertIsInstance(column, sa.Column) | ||||
|             self.assertIsInstance(column.type, sa.String) | ||||
|             self.assertEqual(column.type.length, 32) | ||||
| 
 | ||||
| 
 | ||||
|     class TestUUIDFKColumn(TestCase): | ||||
| 
 | ||||
|         def test_basic(self): | ||||
|             column = mod.uuid_fk_column('foo.bar') | ||||
|             self.assertIsInstance(column, sa.Column) | ||||
|             self.assertIsInstance(column.type, sa.String) | ||||
|             self.assertEqual(column.type.length, 32) | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue