diff --git a/CHANGELOG.md b/CHANGELOG.md index d13957e..2bb633f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,6 @@ * New module `mat` adds a shallow reimplementation of `Matrix()` in order to implement matrix multiplication * Removed obsolete `configparse` implementation that has been around since 0.3 and shelved since 0.4. * `color`: added support for conversion from RGB to sRGB, XYZ, OKLab and OKLCH. -* Added `user-loader` for Quart-Auth and SQLAlchemy ## 0.11.2 diff --git a/pyproject.toml b/pyproject.toml index c020308..eecfddd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ Documentation = "https://suou.readthedocs.io" # the below are all dev dependencies (and probably already installed) sqlalchemy = [ "SQLAlchemy[asyncio]>=2.0.0", - "flask-sqlalchemy" # glue code + "flask-sqlalchemy" ] flask = [ "Flask>=2.0.0", @@ -61,10 +61,6 @@ quart = [ "Quart-Schema", "starlette>=0.47.2" ] -quart_auth = [ - "Quart-Auth", - "suou[sqlalchemy]" # glue code -] sass = [ ## HEADS UP!! libsass carries a C extension + uses setup.py "libsass" @@ -74,7 +70,6 @@ full = [ "suou[sqlalchemy]", "suou[flask]", "suou[quart]", - "suou[quart_auth]", "suou[peewee]", "suou[markdown]", "suou[sass]" diff --git a/src/suou/__init__.py b/src/suou/__init__.py index 27e65f0..ce85766 100644 --- a/src/suou/__init__.py +++ b/src/suou/__init__.py @@ -38,7 +38,7 @@ from .http import WantsContentType from .color import OKLabColor, chalk, WebColor, RGBColor, SRGBColor, XYZColor, OKLabColor from .mat import Matrix -__version__ = "0.12.0a7" +__version__ = "0.12.0a5" __all__ = ( 'ConfigOptions', 'ConfigParserConfigSource', 'ConfigSource', 'ConfigValue', diff --git a/src/suou/color.py b/src/suou/color.py index 13bc362..058fcc7 100644 --- a/src/suou/color.py +++ b/src/suou/color.py @@ -23,7 +23,6 @@ from collections import namedtuple from functools import lru_cache import math -from suou.functools import deprecated from suou.mat import Matrix @@ -103,8 +102,6 @@ class RGBColor(namedtuple('_WebColor', 'red green blue')): Useful for theming. - XXX CURRENTLY THE OKLCH CONVERSION DOES NOT WORK - *Changed in 0.12.0*: name is now RGBColor, with WebColor being an alias. Added conversions to and from OKLCH, OKLab, sRGB, and XYZ. """ @@ -171,7 +168,7 @@ class RGBColor(namedtuple('_WebColor', 'red green blue')): ]) def to_xyz(self): - return XYZColor(*(self.RGB_TO_XYZ @ Matrix.as_column([x / 255 for x in self])).get_column()) + return XYZColor(*(self.RGB_TO_XYZ @ Matrix.as_column(self)).get_column()) def to_oklch(self): return self.to_xyz().to_oklch() @@ -195,9 +192,7 @@ class SRGBColor(namedtuple('_SRGBColor', 'red green blue')): blue: float def __str__(self): - r, g, b = round(self.red, 4), round(self.green, 4), round(self.blue, 4) - - return f"srgb({r}, {g}, {b})" + return f"srgb({self.red}, {self.green}, {self.blue})" def to_rgb(self): return RGBColor(*( @@ -237,8 +232,8 @@ class XYZColor(namedtuple('_XYZColor', 'x y z')): ]) def to_rgb(self): - return RGBColor(*[int(x * 255) for x in (self.XYZ_TO_RGB @ Matrix.as_column(self)).get_column()]) - + return RGBColor(*(self.XYZ_TO_RGB @ Matrix.as_column(self)).get_column()) + def to_oklab(self): lms = (self.XYZ_TO_LMS @ Matrix.as_column(self)).get_column() lmsg = [math.cbrt(i) for i in lms] @@ -248,11 +243,6 @@ class XYZColor(namedtuple('_XYZColor', 'x y z')): def to_oklch(self): return self.to_oklab().to_oklch() - def __str__(self): - x, y, z = round(self.x, 4), round(self.y, 4), round(self.z, 4) - - return f'xyz({x} {y} {z})' - class OKLabColor(namedtuple('_OKLabColor', 'l a b')): """ @@ -286,11 +276,6 @@ class OKLabColor(namedtuple('_OKLabColor', 'l a b')): 0 if abs(self.a) < .0002 and abs(self.b) < .0002 else (((math.atan2(self.b, self.a) * 180) / math.pi % 360) + 360) % 360 ) - def __str__(self): - l, c, h = round(self.l, 4), round(self.a, 4), round(self.b, 4) - - return f'oklab({l} {c} {h})' - def to_rgb(self): return self.to_xyz().to_rgb() @@ -304,18 +289,19 @@ class OKLCHColor(namedtuple('_OKLCHColor', 'l c h')): """ def __str__(self): - l, c, h = round(self.l, 4), round(self.c, 4), round(self.h, 2) + l, c, h = round(self.l, 4), round(self.c, 4), round(self.h, 4) + + return f'oklch({l}, {c}, {h})' - return f'oklch({l} {c} {h})' def to_oklab(self): return OKLabColor( self.l, self.c * math.cos(self.h * math.pi / 180), - self.c * math.sin(self.h * math.pi / 180) + self.h * math.cos(self.h * math.pi / 180) ) def to_rgb(self): return self.to_oklab().to_rgb() -__all__ = ('chalk', 'WebColor', "RGBColor", 'SRGBColor', 'XYZColor', 'OKLabColor', 'OKLCHColor') +__all__ = ('chalk', 'WebColor', "RGBColor", 'SRGBColor', 'XYZColor', 'OKLabColor') diff --git a/src/suou/quart_auth.py b/src/suou/quart_auth.py deleted file mode 100644 index 6797841..0000000 --- a/src/suou/quart_auth.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -Utilities for Quart-Auth - ---- - -Copyright (c) 2025 Sakuragasaki46. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -See LICENSE for the specific language governing permissions and -limitations under the License. - -This software is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -""" - -from __future__ import annotations -from typing import Callable, TypeVar -from quart_auth import AuthUser, Action -from sqlalchemy import select -from sqlalchemy.orm import DeclarativeBase -from .sqlalchemy.asyncio import AsyncSession, SQLAlchemy - -_T = TypeVar('_T') - -def user_loader(database: SQLAlchemy, user_class: type[DeclarativeBase], *, - attr_loader: Callable[[type[AuthUser], str], _T] = lambda x, y: x.id == int(y) - ): - """ - Returns a properly subclassed AuthUser loader for use in Quart-Auth. - - Actual User object is at .user; other attributes are proxied. - - Requires to be awaited before request before usage. - - Uses SQLAlchemy's AsyncSession. - - Parameters: - * database The database instance. - * user_class The user class. - * attr_loader A lambda taking user_class and auth_id, default (user_class, auth_id : user_class.id == int(auth_id)) - - *New in 0.12.0* - """ - class UserLoader(AuthUser): - _auth_id: str | None - _auth_obj: user_class | None - id: _T - - def __init__(self, auth_id: str | None, action: Action = Action.PASS): - self._auth_id = auth_id - self._auth_obj = None - self._auth_sess: AsyncSession | None = None - self.action = action - - @property - def auth_id(self) -> str | None: - return self._auth_id - - @property - async def is_authenticated(self) -> bool: - await self._load() - return self._auth_id is not None - - async def _load(self): - if self._auth_obj is None and self._auth_id is not None: - async with database as session: - self._auth_obj = (await session.execute(select(user_class).where(attr_loader(user_class, self._auth_id)))).scalar() - if self._auth_obj is None: - raise RuntimeError('failed to fetch user') - - def __getattr__(self, key): - if self._auth_obj is None: - raise RuntimeError('user is not loaded') - return getattr(self._auth_obj, key) - - def __bool__(self): - return self._auth_obj is not None - - @property - def session(self): - return self._auth_sess - - async def _unload(self): - # user is not expected to mutate - if self._auth_sess: - await self._auth_sess.rollback() - - @property - def user(self): - return self._auth_obj - - return UserLoader - -# Optional dependency: do not import into __init__.py -__all__ = ('user_loader',) - diff --git a/tests/test_color.py b/tests/test_color.py index dfe4cd3..9b20478 100644 --- a/tests/test_color.py +++ b/tests/test_color.py @@ -2,8 +2,7 @@ import unittest -from suou import RGBColor, chalk -from suou.color import OKLCHColor +from suou import chalk class TestColor(unittest.TestCase): def setUp(self) -> None: @@ -25,9 +24,4 @@ class TestColor(unittest.TestCase): strg = "The quick brown fox jumps over the lazy dog" self.assertEqual(f'\x1b[1m{strg}\x1b[22m', chalk.bold(strg)) self.assertEqual(f'\x1b[2m{strg}\x1b[22m', chalk.faint(strg)) - self.assertEqual(f'\x1b[1m\x1b[33m{strg}\x1b[39m\x1b[22m', chalk.bold.yellow(strg)) - - def test_oklch_to_rgb(self): - self.assertEqual(OKLCHColor(0.628, 0.2577, 29.23).to_rgb(), RGBColor(255, 0, 0)) - self.assertEqual(OKLCHColor(0.7653, 0.1306, 194.77).to_rgb(), RGBColor(0, 204, 204)) - self.assertEqual(OKLCHColor(0.5931, 0., 0.).to_rgb(), RGBColor(126, 126, 126)) \ No newline at end of file + self.assertEqual(f'\x1b[1m\x1b[33m{strg}\x1b[39m\x1b[22m', chalk.bold.yellow(strg)) \ No newline at end of file