2
0
Fork 0

Compare commits

..

No commits in common. "cb147c203db200136010cd1d96b027fa48ea3d97" and "e9507fb5a468a66f44fa0564dc5329aa299096cc" have entirely different histories.

9 changed files with 83 additions and 141 deletions

View file

@ -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

View file

@ -1,6 +0,0 @@
``wuttjamaican.db.util``
========================
.. automodule:: wuttjamaican.db.util
:members:

View file

@ -17,7 +17,6 @@
db.model.base
db.model.upgrades
db.sess
db.util
email
email.handler
email.message

View file

@ -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"}]

View file

@ -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

View file

@ -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`.

View file

@ -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)

View file

@ -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()

View file

@ -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)