Compare commits
No commits in common. "cb147c203db200136010cd1d96b027fa48ea3d97" and "e9507fb5a468a66f44fa0564dc5329aa299096cc" have entirely different histories.
cb147c203d
...
e9507fb5a4
|
@ -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/)
|
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.13.3 (2024-08-30)
|
|
||||||
|
|
||||||
### Fix
|
|
||||||
|
|
||||||
- move model base class out of model subpkg
|
|
||||||
|
|
||||||
## v0.13.2 (2024-08-27)
|
## v0.13.2 (2024-08-27)
|
||||||
|
|
||||||
### Fix
|
### Fix
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
|
|
||||||
``wuttjamaican.db.util``
|
|
||||||
========================
|
|
||||||
|
|
||||||
.. automodule:: wuttjamaican.db.util
|
|
||||||
:members:
|
|
|
@ -17,7 +17,6 @@
|
||||||
db.model.base
|
db.model.base
|
||||||
db.model.upgrades
|
db.model.upgrades
|
||||||
db.sess
|
db.sess
|
||||||
db.util
|
|
||||||
email
|
email
|
||||||
email.handler
|
email.handler
|
||||||
email.message
|
email.message
|
||||||
|
|
|
@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "WuttJamaican"
|
name = "WuttJamaican"
|
||||||
version = "0.13.3"
|
version = "0.13.2"
|
||||||
description = "Base package for Wutta Framework"
|
description = "Base package for Wutta Framework"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
authors = [{name = "Lance Edgar", email = "lance@edbob.org"}]
|
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:
|
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.Base`
|
||||||
* :class:`~wuttjamaican.db.model.base.Setting`
|
* :class:`~wuttjamaican.db.model.base.Setting`
|
||||||
* :class:`~wuttjamaican.db.model.base.Person`
|
* :class:`~wuttjamaican.db.model.base.Person`
|
||||||
|
@ -37,9 +39,6 @@ The ``wuttjamaican.db.model`` namespace contains the following:
|
||||||
* :class:`~wuttjamaican.db.model.upgrades.Upgrade`
|
* :class:`~wuttjamaican.db.model.upgrades.Upgrade`
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: remove these
|
from .base import uuid_column, uuid_fk_column, Base, Setting, Person
|
||||||
from wuttjamaican.db.util import uuid_column, uuid_fk_column
|
|
||||||
|
|
||||||
from .base import Base, Setting, Person
|
|
||||||
from .auth import Role, Permission, User, UserRole
|
from .auth import Role, Permission, User, UserRole
|
||||||
from .upgrades import Upgrade
|
from .upgrades import Upgrade
|
||||||
|
|
|
@ -31,15 +31,62 @@ Base Models
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
from sqlalchemy import orm
|
from sqlalchemy import orm
|
||||||
|
|
||||||
from wuttjamaican.db.util import (naming_convention, ModelBase,
|
from wuttjamaican.util import make_uuid
|
||||||
uuid_column, uuid_fk_column)
|
|
||||||
|
|
||||||
|
|
||||||
|
# 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)
|
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)
|
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):
|
class Setting(Base):
|
||||||
"""
|
"""
|
||||||
Represents a :term:`config setting`.
|
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
|
from unittest import TestCase
|
||||||
|
|
||||||
try:
|
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
|
from wuttjamaican.db.model.auth import User
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
else:
|
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):
|
class TestSetting(TestCase):
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
setting = mod.Setting()
|
setting = model.Setting()
|
||||||
self.assertEqual(str(setting), "")
|
self.assertEqual(str(setting), "")
|
||||||
setting.name = 'foo'
|
setting.name = 'foo'
|
||||||
self.assertEqual(str(setting), "foo")
|
self.assertEqual(str(setting), "foo")
|
||||||
|
@ -20,13 +46,13 @@ else:
|
||||||
class TestPerson(TestCase):
|
class TestPerson(TestCase):
|
||||||
|
|
||||||
def test_basic(self):
|
def test_basic(self):
|
||||||
person = mod.Person()
|
person = model.Person()
|
||||||
self.assertEqual(str(person), "")
|
self.assertEqual(str(person), "")
|
||||||
person.full_name = "Barney Rubble"
|
person.full_name = "Barney Rubble"
|
||||||
self.assertEqual(str(person), "Barney Rubble")
|
self.assertEqual(str(person), "Barney Rubble")
|
||||||
|
|
||||||
def test_users(self):
|
def test_users(self):
|
||||||
person = mod.Person()
|
person = model.Person()
|
||||||
self.assertIsNone(person.user)
|
self.assertIsNone(person.user)
|
||||||
|
|
||||||
user = 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…
Reference in a new issue