Merge branch 'sqlalchemy2' into 'master'

Draft: Upgrade to sqlalchemy 2 & fix db sessions

See merge request archlinux/aurweb!756
This commit is contained in:
Mario Oenning 2023-11-22 21:58:58 +00:00
commit 8db5dc3328
19 changed files with 273 additions and 176 deletions

View file

@ -25,7 +25,7 @@ import aurweb.pkgbase.util as pkgbaseutil
from aurweb import aur_logging, prometheus, util from aurweb import aur_logging, prometheus, util
from aurweb.aur_redis import redis_connection from aurweb.aur_redis import redis_connection
from aurweb.auth import BasicAuthBackend from aurweb.auth import BasicAuthBackend
from aurweb.db import get_engine, query from aurweb.db import get_engine, query, set_db_session_context
from aurweb.models import AcceptedTerm, Term from aurweb.models import AcceptedTerm, Term
from aurweb.packages.util import get_pkg_or_base from aurweb.packages.util import get_pkg_or_base
from aurweb.prometheus import instrumentator from aurweb.prometheus import instrumentator
@ -308,3 +308,20 @@ async def id_redirect_middleware(request: Request, call_next: typing.Callable):
# Add application middlewares. # Add application middlewares.
app.add_middleware(AuthenticationMiddleware, backend=BasicAuthBackend()) app.add_middleware(AuthenticationMiddleware, backend=BasicAuthBackend())
app.add_middleware(SessionMiddleware, secret_key=session_secret) app.add_middleware(SessionMiddleware, secret_key=session_secret)
# Set context var for database session & remove it after our request
@app.middleware("http")
async def db_session_context(request: Request, call_next: typing.Callable):
# static content won't require a db session
if request.url.path.startswith("/static"):
return await util.error_or_result(call_next, request)
try:
set_db_session_context(hash(request))
response = await util.error_or_result(call_next, request)
finally:
set_db_session_context(None)
return response

View file

@ -1,7 +1,39 @@
from contextvars import ContextVar
from threading import get_ident
from typing import Optional
# Supported database drivers. # Supported database drivers.
DRIVERS = {"mysql": "mysql+mysqldb"} DRIVERS = {"mysql": "mysql+mysqldb"}
class Committer:
def __init__(self, session):
self.session = session
def __enter__(self):
pass
def __exit__(self, *args):
self.session.commit()
db_session_context: ContextVar[Optional[int]] = ContextVar(
"session_id", default=get_ident()
)
def get_db_session_context():
id = db_session_context.get()
return id
def set_db_session_context(session_id: int):
if session_id is None:
get_session().remove()
db_session_context.set(session_id)
def make_random_value(table: str, column: str, length: int): def make_random_value(table: str, column: str, length: int):
"""Generate a unique, random value for a string column in a table. """Generate a unique, random value for a string column in a table.
@ -61,38 +93,39 @@ def name() -> str:
return "db" + sha1 return "db" + sha1
# Module-private global memo used to store SQLAlchemy sessions. # Module-private global memo used to store SQLAlchemy sessions registries.
_sessions = dict() _session_registries = dict()
def get_session(engine=None): def get_session(engine=None):
"""Return aurweb.db's global session.""" """Return aurweb.db's global session."""
dbname = name() dbname = name()
global _sessions global _session_registries
if dbname not in _sessions: if dbname not in _session_registries:
from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.orm import scoped_session, sessionmaker
if not engine: # pragma: no cover if not engine: # pragma: no cover
engine = get_engine() engine = get_engine()
Session = scoped_session( Session = scoped_session(
sessionmaker(autocommit=True, autoflush=False, bind=engine) sessionmaker(autoflush=False, bind=engine),
scopefunc=get_db_session_context,
) )
_sessions[dbname] = Session() _session_registries[dbname] = Session
return _sessions.get(dbname) return _session_registries.get(dbname)
def pop_session(dbname: str) -> None: def pop_session(dbname: str) -> None:
""" """
Pop a Session out of the private _sessions memo. Pop a Session registry out of the private _session_registries memo.
:param dbname: Database name :param dbname: Database name
:raises KeyError: When `dbname` does not exist in the memo :raises KeyError: When `dbname` does not exist in the memo
""" """
global _sessions global _session_registries
_sessions.pop(dbname) _session_registries.pop(dbname)
def refresh(model): def refresh(model):
@ -158,7 +191,7 @@ def add(model):
def begin(): def begin():
"""Begin an SQLAlchemy SessionTransaction.""" """Begin an SQLAlchemy SessionTransaction."""
return get_session().begin() return Committer(get_session())
def retry_deadlock(func): def retry_deadlock(func):
@ -217,7 +250,7 @@ def get_sqlalchemy_url():
parts = sqlalchemy.__version__.split(".") parts = sqlalchemy.__version__.split(".")
major = int(parts[0]) major = int(parts[0])
minor = int(parts[1]) minor = int(parts[1])
if major == 1 and minor >= 4: # pragma: no cover if (major == 1 and minor >= 4) or (major == 2): # pragma: no cover
constructor = URL.create constructor = URL.create
aur_db_backend = aurweb.config.get("database", "backend") aur_db_backend = aurweb.config.get("database", "backend")
@ -292,12 +325,14 @@ def get_engine(dbname: str = None, echo: bool = False):
if dbname not in _engines: if dbname not in _engines:
db_backend = aurweb.config.get("database", "backend") db_backend = aurweb.config.get("database", "backend")
connect_args = dict() connect_args = dict()
kwargs = {"echo": echo, "connect_args": connect_args}
is_sqlite = bool(db_backend == "sqlite") is_sqlite = bool(db_backend == "sqlite")
if is_sqlite: # pragma: no cover if is_sqlite: # pragma: no cover
connect_args["check_same_thread"] = False connect_args["check_same_thread"] = False
else:
kwargs["isolation_level"] = "READ_COMMITTED"
kwargs = {"echo": echo, "connect_args": connect_args}
from sqlalchemy import create_engine from sqlalchemy import create_engine
_engines[dbname] = create_engine(get_sqlalchemy_url(), **kwargs) _engines[dbname] = create_engine(get_sqlalchemy_url(), **kwargs)

View file

@ -59,7 +59,8 @@ def run(args):
engine = aurweb.db.get_engine(echo=(args.verbose >= 1)) engine = aurweb.db.get_engine(echo=(args.verbose >= 1))
aurweb.schema.metadata.create_all(engine) aurweb.schema.metadata.create_all(engine)
conn = engine.connect() conn = engine.connect()
feed_initial_data(conn) with conn.begin():
feed_initial_data(conn)
conn.close() conn.close()
if args.use_alembic: if args.use_alembic:

View file

@ -1,6 +1,6 @@
import json import json
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import declarative_base
from aurweb import util from aurweb import util

View file

@ -210,7 +210,7 @@ class PackageSearch:
# in terms of performance. We should improve this; there's no # in terms of performance. We should improve this; there's no
# reason it should take _longer_. # reason it should take _longer_.
column = getattr( column = getattr(
case([(models.PackageVote.UsersID == self.user.ID, 1)], else_=0), order case((models.PackageVote.UsersID == self.user.ID, 1), else_=0), order
) )
name = getattr(models.Package.Name, order) name = getattr(models.Package.Name, order)
self.query = self.query.order_by(column(), name()) self.query = self.query.order_by(column(), name())
@ -221,7 +221,7 @@ class PackageSearch:
# in terms of performance. We should improve this; there's no # in terms of performance. We should improve this; there's no
# reason it should take _longer_. # reason it should take _longer_.
column = getattr( column = getattr(
case([(models.PackageNotification.UserID == self.user.ID, 1)], else_=0), case((models.PackageNotification.UserID == self.user.ID, 1), else_=0),
order, order,
) )
name = getattr(models.Package.Name, order) name = getattr(models.Package.Name, order)

View file

@ -145,7 +145,7 @@ async def index(request: Request):
.order_by( .order_by(
# Order primarily by the Status column being PENDING_ID, # Order primarily by the Status column being PENDING_ID,
# and secondarily by RequestTS; both in descending order. # and secondarily by RequestTS; both in descending order.
case([(models.PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(), case((models.PackageRequest.Status == PENDING_ID, 1), else_=0).desc(),
models.PackageRequest.RequestTS.desc(), models.PackageRequest.RequestTS.desc(),
) )
.limit(50) .limit(50)

View file

@ -110,7 +110,7 @@ async def requests( # noqa: C901
filtered.order_by( filtered.order_by(
# Order primarily by the Status column being PENDING_ID, # Order primarily by the Status column being PENDING_ID,
# and secondarily by RequestTS; both in descending order. # and secondarily by RequestTS; both in descending order.
case([(PackageRequest.Status == PENDING_ID, 1)], else_=0).desc(), case((PackageRequest.Status == PENDING_ID, 1), else_=0).desc(),
PackageRequest.RequestTS.desc(), PackageRequest.RequestTS.desc(),
) )
.limit(PP) .limit(PP)

View file

@ -1,3 +1,5 @@
from sqlalchemy import text
import aurweb.db import aurweb.db
from aurweb import models from aurweb import models
@ -56,8 +58,10 @@ def setup_test_db(*args):
models.User.__tablename__, models.User.__tablename__,
] ]
aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 0") session = aurweb.db.get_session()
session.execute(text("SET FOREIGN_KEY_CHECKS = 0"))
for table in tables: for table in tables:
aurweb.db.get_session().execute(f"DELETE FROM {table}") session.execute(text(f"DELETE FROM {table}"))
aurweb.db.get_session().execute("SET FOREIGN_KEY_CHECKS = 1") session.execute(text("SET FOREIGN_KEY_CHECKS = 1"))
aurweb.db.get_session().expunge_all() session.expunge_all()
session.commit()

257
poetry.lock generated
View file

@ -32,13 +32,13 @@ tz = ["python-dateutil"]
[[package]] [[package]]
name = "annotated-types" name = "annotated-types"
version = "0.5.0" version = "0.6.0"
description = "Reusable constraint types to use with typing.Annotated" description = "Reusable constraint types to use with typing.Annotated"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"},
{file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
] ]
[[package]] [[package]]
@ -140,13 +140,13 @@ typecheck = ["mypy"]
[[package]] [[package]]
name = "bleach" name = "bleach"
version = "6.0.0" version = "6.1.0"
description = "An easy safelist-based HTML-sanitizing tool." description = "An easy safelist-based HTML-sanitizing tool."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "bleach-6.0.0-py3-none-any.whl", hash = "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"}, {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"},
{file = "bleach-6.0.0.tar.gz", hash = "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414"}, {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"},
] ]
[package.dependencies] [package.dependencies]
@ -154,7 +154,7 @@ six = ">=1.9.0"
webencodings = "*" webencodings = "*"
[package.extras] [package.extras]
css = ["tinycss2 (>=1.1.0,<1.2)"] css = ["tinycss2 (>=1.1.0,<1.3)"]
[[package]] [[package]]
name = "certifi" name = "certifi"
@ -1007,20 +1007,20 @@ testing = ["pytest"]
[[package]] [[package]]
name = "markdown" name = "markdown"
version = "3.4.4" version = "3.5"
description = "Python implementation of John Gruber's Markdown." description = "Python implementation of John Gruber's Markdown."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"}, {file = "Markdown-3.5-py3-none-any.whl", hash = "sha256:4afb124395ce5fc34e6d9886dab977fd9ae987fc6e85689f08278cf0c69d4bf3"},
{file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"}, {file = "Markdown-3.5.tar.gz", hash = "sha256:a807eb2e4778d9156c8f07876c6e4d50b5494c5665c4834f67b06459dfd877b3"},
] ]
[package.dependencies] [package.dependencies]
importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""}
[package.extras] [package.extras]
docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"] docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
testing = ["coverage", "pyyaml"] testing = ["coverage", "pyyaml"]
[[package]] [[package]]
@ -1110,71 +1110,61 @@ files = [
[[package]] [[package]]
name = "orjson" name = "orjson"
version = "3.9.7" version = "3.9.9"
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "orjson-3.9.7-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6df858e37c321cefbf27fe7ece30a950bcc3a75618a804a0dcef7ed9dd9c92d"}, {file = "orjson-3.9.9-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f28090060a31f4d11221f9ba48b2273b0d04b702f4dcaa197c38c64ce639cc51"},
{file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5198633137780d78b86bb54dafaaa9baea698b4f059456cd4554ab7009619221"}, {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8038ba245d0c0a6337cfb6747ea0c51fe18b0cf1a4bc943d530fd66799fae33d"},
{file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e736815b30f7e3c9044ec06a98ee59e217a833227e10eb157f44071faddd7c5"}, {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:543b36df56db195739c70d645ecd43e49b44d5ead5f8f645d2782af118249b37"},
{file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a19e4074bc98793458b4b3ba35a9a1d132179345e60e152a1bb48c538ab863c4"}, {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e7877256b5092f1e4e48fc0f1004728dc6901e7a4ffaa4acb0a9578610aa4ce"},
{file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80acafe396ab689a326ab0d80f8cc61dec0dd2c5dca5b4b3825e7b1e0132c101"}, {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12b83e0d8ba4ca88b894c3e00efc59fe6d53d9ffb5dbbb79d437a466fc1a513d"},
{file = "orjson-3.9.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:355efdbbf0cecc3bd9b12589b8f8e9f03c813a115efa53f8dc2a523bfdb01334"}, {file = "orjson-3.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ef06431f021453a47a9abb7f7853f04f031d31fbdfe1cc83e3c6aadde502cce"},
{file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3aab72d2cef7f1dd6104c89b0b4d6b416b0db5ca87cc2fac5f79c5601f549cc2"}, {file = "orjson-3.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0a1a4d9e64597e550428ba091e51a4bcddc7a335c8f9297effbfa67078972b5c"},
{file = "orjson-3.9.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36b1df2e4095368ee388190687cb1b8557c67bc38400a942a1a77713580b50ae"}, {file = "orjson-3.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:879d2d1f6085c9c0831cec6716c63aaa89e41d8e036cabb19a315498c173fcc6"},
{file = "orjson-3.9.7-cp310-none-win32.whl", hash = "sha256:e94b7b31aa0d65f5b7c72dd8f8227dbd3e30354b99e7a9af096d967a77f2a580"}, {file = "orjson-3.9.9-cp310-none-win32.whl", hash = "sha256:d3f56e41bc79d30fdf077073072f2377d2ebf0b946b01f2009ab58b08907bc28"},
{file = "orjson-3.9.7-cp310-none-win_amd64.whl", hash = "sha256:82720ab0cf5bb436bbd97a319ac529aee06077ff7e61cab57cee04a596c4f9b4"}, {file = "orjson-3.9.9-cp310-none-win_amd64.whl", hash = "sha256:ab7bae2b8bf17620ed381e4101aeeb64b3ba2a45fc74c7617c633a923cb0f169"},
{file = "orjson-3.9.7-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1f8b47650f90e298b78ecf4df003f66f54acdba6a0f763cc4df1eab048fe3738"}, {file = "orjson-3.9.9-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:31d676bc236f6e919d100fb85d0a99812cff1ebffaa58106eaaec9399693e227"},
{file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f738fee63eb263530efd4d2e9c76316c1f47b3bbf38c1bf45ae9625feed0395e"}, {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:678ffb5c0a6b1518b149cc328c610615d70d9297e351e12c01d0beed5d65360f"},
{file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38e34c3a21ed41a7dbd5349e24c3725be5416641fdeedf8f56fcbab6d981c900"}, {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a71b0cc21f2c324747bc77c35161e0438e3b5e72db6d3b515310457aba743f7f"},
{file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21a3344163be3b2c7e22cef14fa5abe957a892b2ea0525ee86ad8186921b6cf0"}, {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae72621f216d1d990468291b1ec153e1b46e0ed188a86d54e0941f3dabd09ee8"},
{file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23be6b22aab83f440b62a6f5975bcabeecb672bc627face6a83bc7aeb495dc7e"}, {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:512e5a41af008e76451f5a344941d61f48dddcf7d7ddd3073deb555de64596a6"},
{file = "orjson-3.9.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5205ec0dfab1887dd383597012199f5175035e782cdb013c542187d280ca443"}, {file = "orjson-3.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f89dc338a12f4357f5bf1b098d3dea6072fb0b643fd35fec556f4941b31ae27"},
{file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8769806ea0b45d7bf75cad253fba9ac6700b7050ebb19337ff6b4e9060f963fa"}, {file = "orjson-3.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:957a45fb201c61b78bcf655a16afbe8a36c2c27f18a998bd6b5d8a35e358d4ad"},
{file = "orjson-3.9.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f9e01239abea2f52a429fe9d95c96df95f078f0172489d691b4a848ace54a476"}, {file = "orjson-3.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1c01cf4b8e00c7e98a0a7cf606a30a26c32adf2560be2d7d5d6766d6f474b31"},
{file = "orjson-3.9.7-cp311-none-win32.whl", hash = "sha256:8bdb6c911dae5fbf110fe4f5cba578437526334df381b3554b6ab7f626e5eeca"}, {file = "orjson-3.9.9-cp311-none-win32.whl", hash = "sha256:397a185e5dd7f8ebe88a063fe13e34d61d394ebb8c70a443cee7661b9c89bda7"},
{file = "orjson-3.9.7-cp311-none-win_amd64.whl", hash = "sha256:9d62c583b5110e6a5cf5169ab616aa4ec71f2c0c30f833306f9e378cf51b6c86"}, {file = "orjson-3.9.9-cp311-none-win_amd64.whl", hash = "sha256:24301f2d99d670ded4fb5e2f87643bc7428a54ba49176e38deb2887e42fe82fb"},
{file = "orjson-3.9.7-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:1c3cee5c23979deb8d1b82dc4cc49be59cccc0547999dbe9adb434bb7af11cf7"}, {file = "orjson-3.9.9-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bd55ea5cce3addc03f8fb0705be0cfed63b048acc4f20914ce5e1375b15a293b"},
{file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a347d7b43cb609e780ff8d7b3107d4bcb5b6fd09c2702aa7bdf52f15ed09fa09"}, {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b28c1a65cd13fff5958ab8b350f0921121691464a7a1752936b06ed25c0c7b6e"},
{file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:154fd67216c2ca38a2edb4089584504fbb6c0694b518b9020ad35ecc97252bb9"}, {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b97a67c47840467ccf116136450c50b6ed4e16a8919c81a4b4faef71e0a2b3f4"},
{file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ea3e63e61b4b0beeb08508458bdff2daca7a321468d3c4b320a758a2f554d31"}, {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75b805549cbbcb963e9c9068f1a05abd0ea4c34edc81f8d8ef2edb7e139e5b0f"},
{file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb0b0b2476f357eb2975ff040ef23978137aa674cd86204cfd15d2d17318588"}, {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5424ecbafe57b2de30d3b5736c5d5835064d522185516a372eea069b92786ba6"},
{file = "orjson-3.9.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b9a20a03576c6b7022926f614ac5a6b0914486825eac89196adf3267c6489d"}, {file = "orjson-3.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d2cd6ef4726ef1b8c63e30d8287225a383dbd1de3424d287b37c1906d8d2855"},
{file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:915e22c93e7b7b636240c5a79da5f6e4e84988d699656c8e27f2ac4c95b8dcc0"}, {file = "orjson-3.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c959550e0705dc9f59de8fca1a316da0d9b115991806b217c82931ac81d75f74"},
{file = "orjson-3.9.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f26fb3e8e3e2ee405c947ff44a3e384e8fa1843bc35830fe6f3d9a95a1147b6e"}, {file = "orjson-3.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ece2d8ed4c34903e7f1b64fb1e448a00e919a4cdb104fc713ad34b055b665fca"},
{file = "orjson-3.9.7-cp312-none-win_amd64.whl", hash = "sha256:d8692948cada6ee21f33db5e23460f71c8010d6dfcfe293c9b96737600a7df78"}, {file = "orjson-3.9.9-cp312-none-win_amd64.whl", hash = "sha256:f708ca623287186e5876256cb30599308bce9b2757f90d917b7186de54ce6547"},
{file = "orjson-3.9.7-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:7bab596678d29ad969a524823c4e828929a90c09e91cc438e0ad79b37ce41166"}, {file = "orjson-3.9.9-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:335406231f9247f985df045f0c0c8f6b6d5d6b3ff17b41a57c1e8ef1a31b4d04"},
{file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63ef3d371ea0b7239ace284cab9cd00d9c92b73119a7c274b437adb09bda35e6"}, {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d9b5440a5d215d9e1cfd4aee35fd4101a8b8ceb8329f549c16e3894ed9f18b5"},
{file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f8fcf696bbbc584c0c7ed4adb92fd2ad7d153a50258842787bc1524e50d7081"}, {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e98ca450cb4fb176dd572ce28c6623de6923752c70556be4ef79764505320acb"},
{file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90fe73a1f0321265126cbba13677dcceb367d926c7a65807bd80916af4c17047"}, {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3bf6ca6bce22eb89dd0650ef49c77341440def966abcb7a2d01de8453df083a"},
{file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45a47f41b6c3beeb31ac5cf0ff7524987cfcce0a10c43156eb3ee8d92d92bf22"}, {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb50d869b3c97c7c5187eda3759e8eb15deb1271d694bc5d6ba7040db9e29036"},
{file = "orjson-3.9.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a2937f528c84e64be20cb80e70cea76a6dfb74b628a04dab130679d4454395c"}, {file = "orjson-3.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fcf06c69ccc78e32d9f28aa382ab2ab08bf54b696dbe00ee566808fdf05da7d"},
{file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b4fb306c96e04c5863d52ba8d65137917a3d999059c11e659eba7b75a69167bd"}, {file = "orjson-3.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9a4402e7df1b5c9a4c71c7892e1c8f43f642371d13c73242bda5964be6231f95"},
{file = "orjson-3.9.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:410aa9d34ad1089898f3db461b7b744d0efcf9252a9415bbdf23540d4f67589f"}, {file = "orjson-3.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b20becf50d4aec7114dc902b58d85c6431b3a59b04caa977e6ce67b6fee0e159"},
{file = "orjson-3.9.7-cp37-none-win32.whl", hash = "sha256:26ffb398de58247ff7bde895fe30817a036f967b0ad0e1cf2b54bda5f8dcfdd9"}, {file = "orjson-3.9.9-cp38-none-win32.whl", hash = "sha256:1f352117eccac268a59fedac884b0518347f5e2b55b9f650c2463dd1e732eb61"},
{file = "orjson-3.9.7-cp37-none-win_amd64.whl", hash = "sha256:bcb9a60ed2101af2af450318cd89c6b8313e9f8df4e8fb12b657b2e97227cf08"}, {file = "orjson-3.9.9-cp38-none-win_amd64.whl", hash = "sha256:c4eb31a8e8a5e1d9af5aa9e247c2a52ad5cf7e968aaa9aaefdff98cfcc7f2e37"},
{file = "orjson-3.9.7-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5da9032dac184b2ae2da4bce423edff7db34bfd936ebd7d4207ea45840f03905"}, {file = "orjson-3.9.9-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4a308aeac326c2bafbca9abbae1e1fcf682b06e78a54dad0347b760525838d85"},
{file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7951af8f2998045c656ba8062e8edf5e83fd82b912534ab1de1345de08a41d2b"}, {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e159b97f5676dcdac0d0f75ec856ef5851707f61d262851eb41a30e8fadad7c9"},
{file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b8e59650292aa3a8ea78073fc84184538783966528e442a1b9ed653aa282edcf"}, {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f692e7aabad92fa0fff5b13a846fb586b02109475652207ec96733a085019d80"},
{file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9274ba499e7dfb8a651ee876d80386b481336d3868cba29af839370514e4dce0"}, {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cffb77cf0cd3cbf20eb603f932e0dde51b45134bdd2d439c9f57924581bb395b"},
{file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca1706e8b8b565e934c142db6a9592e6401dc430e4b067a97781a997070c5378"}, {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c63eca397127ebf46b59c9c1fb77b30dd7a8fc808ac385e7a58a7e64bae6e106"},
{file = "orjson-3.9.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cc275cf6dcb1a248e1876cdefd3f9b5f01063854acdfd687ec360cd3c9712a"}, {file = "orjson-3.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f0c024a75e8ba5d9101facb4fb5a028cdabe3cdfe081534f2a9de0d5062af2"},
{file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:11c10f31f2c2056585f89d8229a56013bc2fe5de51e095ebc71868d070a8dd81"}, {file = "orjson-3.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8cba20c9815c2a003b8ca4429b0ad4aa87cb6649af41365821249f0fd397148e"},
{file = "orjson-3.9.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cf334ce1d2fadd1bf3e5e9bf15e58e0c42b26eb6590875ce65bd877d917a58aa"}, {file = "orjson-3.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:906cac73b7818c20cf0f6a7dde5a6f009c52aecc318416c7af5ea37f15ca7e66"},
{file = "orjson-3.9.7-cp38-none-win32.whl", hash = "sha256:76a0fc023910d8a8ab64daed8d31d608446d2d77c6474b616b34537aa7b79c7f"}, {file = "orjson-3.9.9-cp39-none-win32.whl", hash = "sha256:50232572dd300c49f134838c8e7e0917f29a91f97dbd608d23f2895248464b7f"},
{file = "orjson-3.9.7-cp38-none-win_amd64.whl", hash = "sha256:7a34a199d89d82d1897fd4a47820eb50947eec9cda5fd73f4578ff692a912f89"}, {file = "orjson-3.9.9-cp39-none-win_amd64.whl", hash = "sha256:920814e02e3dd7af12f0262bbc18b9fe353f75a0d0c237f6a67d270da1a1bb44"},
{file = "orjson-3.9.7-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e7e7f44e091b93eb39db88bb0cb765db09b7a7f64aea2f35e7d86cbf47046c65"}, {file = "orjson-3.9.9.tar.gz", hash = "sha256:02e693843c2959befdd82d1ebae8b05ed12d1cb821605d5f9fe9f98ca5c9fd2b"},
{file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01d647b2a9c45a23a84c3e70e19d120011cba5f56131d185c1b78685457320bb"},
{file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0eb850a87e900a9c484150c414e21af53a6125a13f6e378cf4cc11ae86c8f9c5"},
{file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f4b0042d8388ac85b8330b65406c84c3229420a05068445c13ca28cc222f1f7"},
{file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd3e7aae977c723cc1dbb82f97babdb5e5fbce109630fbabb2ea5053523c89d3"},
{file = "orjson-3.9.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c616b796358a70b1f675a24628e4823b67d9e376df2703e893da58247458956"},
{file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c3ba725cf5cf87d2d2d988d39c6a2a8b6fc983d78ff71bc728b0be54c869c884"},
{file = "orjson-3.9.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4891d4c934f88b6c29b56395dfc7014ebf7e10b9e22ffd9877784e16c6b2064f"},
{file = "orjson-3.9.7-cp39-none-win32.whl", hash = "sha256:14d3fb6cd1040a4a4a530b28e8085131ed94ebc90d72793c59a713de34b60838"},
{file = "orjson-3.9.7-cp39-none-win_amd64.whl", hash = "sha256:9ef82157bbcecd75d6296d5d8b2d792242afcd064eb1ac573f8847b52e58f677"},
{file = "orjson-3.9.7.tar.gz", hash = "sha256:85e39198f78e2f7e054d296395f6c96f5e02892337746ef5b6a1bf3ed5910142"},
] ]
[[package]] [[package]]
@ -1687,73 +1677,88 @@ files = [
[[package]] [[package]]
name = "sqlalchemy" name = "sqlalchemy"
version = "1.4.49" version = "2.0.22"
description = "Database Abstraction Library" description = "Database Abstraction Library"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" python-versions = ">=3.7"
files = [ files = [
{file = "SQLAlchemy-1.4.49-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e126cf98b7fd38f1e33c64484406b78e937b1a280e078ef558b95bf5b6895f6"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f146c61ae128ab43ea3a0955de1af7e1633942c2b2b4985ac51cc292daf33222"},
{file = "SQLAlchemy-1.4.49-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:03db81b89fe7ef3857b4a00b63dedd632d6183d4ea5a31c5d8a92e000a41fc71"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:875de9414393e778b655a3d97d60465eb3fae7c919e88b70cc10b40b9f56042d"},
{file = "SQLAlchemy-1.4.49-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:95b9df9afd680b7a3b13b38adf6e3a38995da5e162cc7524ef08e3be4e5ed3e1"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13790cb42f917c45c9c850b39b9941539ca8ee7917dacf099cc0b569f3d40da7"},
{file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a63e43bf3f668c11bb0444ce6e809c1227b8f067ca1068898f3008a273f52b09"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e04ab55cf49daf1aeb8c622c54d23fa4bec91cb051a43cc24351ba97e1dd09f5"},
{file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f835c050ebaa4e48b18403bed2c0fda986525896efd76c245bdd4db995e51a4c"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a42c9fa3abcda0dcfad053e49c4f752eef71ecd8c155221e18b99d4224621176"},
{file = "SQLAlchemy-1.4.49-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c21b172dfb22e0db303ff6419451f0cac891d2e911bb9fbf8003d717f1bcf91"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:14cd3bcbb853379fef2cd01e7c64a5d6f1d005406d877ed9509afb7a05ff40a5"},
{file = "SQLAlchemy-1.4.49-cp310-cp310-win32.whl", hash = "sha256:5fb1ebdfc8373b5a291485757bd6431de8d7ed42c27439f543c81f6c8febd729"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-win32.whl", hash = "sha256:d143c5a9dada696bcfdb96ba2de4a47d5a89168e71d05a076e88a01386872f97"},
{file = "SQLAlchemy-1.4.49-cp310-cp310-win_amd64.whl", hash = "sha256:f8a65990c9c490f4651b5c02abccc9f113a7f56fa482031ac8cb88b70bc8ccaa"}, {file = "SQLAlchemy-2.0.22-cp310-cp310-win_amd64.whl", hash = "sha256:ccd87c25e4c8559e1b918d46b4fa90b37f459c9b4566f1dfbce0eb8122571547"},
{file = "SQLAlchemy-1.4.49-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8923dfdf24d5aa8a3adb59723f54118dd4fe62cf59ed0d0d65d940579c1170a4"}, {file = "SQLAlchemy-2.0.22-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f6ff392b27a743c1ad346d215655503cec64405d3b694228b3454878bf21590"},
{file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9ab2c507a7a439f13ca4499db6d3f50423d1d65dc9b5ed897e70941d9e135b0"}, {file = "SQLAlchemy-2.0.22-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f776c2c30f0e5f4db45c3ee11a5f2a8d9de68e81eb73ec4237de1e32e04ae81c"},
{file = "SQLAlchemy-1.4.49-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5debe7d49b8acf1f3035317e63d9ec8d5e4d904c6e75a2a9246a119f5f2fdf3d"}, {file = "SQLAlchemy-2.0.22-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8f1792d20d2f4e875ce7a113f43c3561ad12b34ff796b84002a256f37ce9437"},
{file = "SQLAlchemy-1.4.49-cp311-cp311-win32.whl", hash = "sha256:82b08e82da3756765c2e75f327b9bf6b0f043c9c3925fb95fb51e1567fa4ee87"}, {file = "SQLAlchemy-2.0.22-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d80eeb5189d7d4b1af519fc3f148fe7521b9dfce8f4d6a0820e8f5769b005051"},
{file = "SQLAlchemy-1.4.49-cp311-cp311-win_amd64.whl", hash = "sha256:171e04eeb5d1c0d96a544caf982621a1711d078dbc5c96f11d6469169bd003f1"}, {file = "SQLAlchemy-2.0.22-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:69fd9e41cf9368afa034e1c81f3570afb96f30fcd2eb1ef29cb4d9371c6eece2"},
{file = "SQLAlchemy-1.4.49-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:36e58f8c4fe43984384e3fbe6341ac99b6b4e083de2fe838f0fdb91cebe9e9cb"}, {file = "SQLAlchemy-2.0.22-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54bcceaf4eebef07dadfde424f5c26b491e4a64e61761dea9459103ecd6ccc95"},
{file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b31e67ff419013f99ad6f8fc73ee19ea31585e1e9fe773744c0f3ce58c039c30"}, {file = "SQLAlchemy-2.0.22-cp311-cp311-win32.whl", hash = "sha256:7ee7ccf47aa503033b6afd57efbac6b9e05180f492aeed9fcf70752556f95624"},
{file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c14b29d9e1529f99efd550cd04dbb6db6ba5d690abb96d52de2bff4ed518bc95"}, {file = "SQLAlchemy-2.0.22-cp311-cp311-win_amd64.whl", hash = "sha256:b560f075c151900587ade06706b0c51d04b3277c111151997ea0813455378ae0"},
{file = "SQLAlchemy-1.4.49-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c40f3470e084d31247aea228aa1c39bbc0904c2b9ccbf5d3cfa2ea2dac06f26d"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2c9bac865ee06d27a1533471405ad240a6f5d83195eca481f9fc4a71d8b87df8"},
{file = "SQLAlchemy-1.4.49-cp36-cp36m-win32.whl", hash = "sha256:706bfa02157b97c136547c406f263e4c6274a7b061b3eb9742915dd774bbc264"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:625b72d77ac8ac23da3b1622e2da88c4aedaee14df47c8432bf8f6495e655de2"},
{file = "SQLAlchemy-1.4.49-cp36-cp36m-win_amd64.whl", hash = "sha256:a7f7b5c07ae5c0cfd24c2db86071fb2a3d947da7bd487e359cc91e67ac1c6d2e"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b39a6e21110204a8c08d40ff56a73ba542ec60bab701c36ce721e7990df49fb9"},
{file = "SQLAlchemy-1.4.49-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:4afbbf5ef41ac18e02c8dc1f86c04b22b7a2125f2a030e25bbb4aff31abb224b"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53a766cb0b468223cafdf63e2d37f14a4757476157927b09300c8c5832d88560"},
{file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24e300c0c2147484a002b175f4e1361f102e82c345bf263242f0449672a4bccf"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0e1ce8ebd2e040357dde01a3fb7d30d9b5736b3e54a94002641dfd0aa12ae6ce"},
{file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:201de072b818f8ad55c80d18d1a788729cccf9be6d9dc3b9d8613b053cd4836d"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:505f503763a767556fa4deae5194b2be056b64ecca72ac65224381a0acab7ebe"},
{file = "SQLAlchemy-1.4.49-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7653ed6817c710d0c95558232aba799307d14ae084cc9b1f4c389157ec50df5c"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-win32.whl", hash = "sha256:154a32f3c7b00de3d090bc60ec8006a78149e221f1182e3edcf0376016be9396"},
{file = "SQLAlchemy-1.4.49-cp37-cp37m-win32.whl", hash = "sha256:647e0b309cb4512b1f1b78471fdaf72921b6fa6e750b9f891e09c6e2f0e5326f"}, {file = "SQLAlchemy-2.0.22-cp312-cp312-win_amd64.whl", hash = "sha256:129415f89744b05741c6f0b04a84525f37fbabe5dc3774f7edf100e7458c48cd"},
{file = "SQLAlchemy-1.4.49-cp37-cp37m-win_amd64.whl", hash = "sha256:ab73ed1a05ff539afc4a7f8cf371764cdf79768ecb7d2ec691e3ff89abbc541e"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3940677d341f2b685a999bffe7078697b5848a40b5f6952794ffcf3af150c301"},
{file = "SQLAlchemy-1.4.49-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:37ce517c011560d68f1ffb28af65d7e06f873f191eb3a73af5671e9c3fada08a"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55914d45a631b81a8a2cb1a54f03eea265cf1783241ac55396ec6d735be14883"},
{file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1878ce508edea4a879015ab5215546c444233881301e97ca16fe251e89f1c55"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2096d6b018d242a2bcc9e451618166f860bb0304f590d205173d317b69986c95"},
{file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0e8e608983e6f85d0852ca61f97e521b62e67969e6e640fe6c6b575d4db68557"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:19c6986cf2fb4bc8e0e846f97f4135a8e753b57d2aaaa87c50f9acbe606bd1db"},
{file = "SQLAlchemy-1.4.49-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccf956da45290df6e809ea12c54c02ace7f8ff4d765d6d3dfb3655ee876ce58d"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6ac28bd6888fe3c81fbe97584eb0b96804bd7032d6100b9701255d9441373ec1"},
{file = "SQLAlchemy-1.4.49-cp38-cp38-win32.whl", hash = "sha256:f167c8175ab908ce48bd6550679cc6ea20ae169379e73c7720a28f89e53aa532"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-win32.whl", hash = "sha256:cb9a758ad973e795267da334a92dd82bb7555cb36a0960dcabcf724d26299db8"},
{file = "SQLAlchemy-1.4.49-cp38-cp38-win_amd64.whl", hash = "sha256:45806315aae81a0c202752558f0df52b42d11dd7ba0097bf71e253b4215f34f4"}, {file = "SQLAlchemy-2.0.22-cp37-cp37m-win_amd64.whl", hash = "sha256:40b1206a0d923e73aa54f0a6bd61419a96b914f1cd19900b6c8226899d9742ad"},
{file = "SQLAlchemy-1.4.49-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:b6d0c4b15d65087738a6e22e0ff461b407533ff65a73b818089efc8eb2b3e1de"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3aa1472bf44f61dd27987cd051f1c893b7d3b17238bff8c23fceaef4f1133868"},
{file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a843e34abfd4c797018fd8d00ffffa99fd5184c421f190b6ca99def4087689bd"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:56a7e2bb639df9263bf6418231bc2a92a773f57886d371ddb7a869a24919face"},
{file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1c890421651b45a681181301b3497e4d57c0d01dc001e10438a40e9a9c25ee77"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccca778c0737a773a1ad86b68bda52a71ad5950b25e120b6eb1330f0df54c3d0"},
{file = "SQLAlchemy-1.4.49-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d26f280b8f0a8f497bc10573849ad6dc62e671d2468826e5c748d04ed9e670d5"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6c3e9350f9fb16de5b5e5fbf17b578811a52d71bb784cc5ff71acb7de2a7f9"},
{file = "SQLAlchemy-1.4.49-cp39-cp39-win32.whl", hash = "sha256:ec2268de67f73b43320383947e74700e95c6770d0c68c4e615e9897e46296294"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:564e9f9e4e6466273dbfab0e0a2e5fe819eec480c57b53a2cdee8e4fdae3ad5f"},
{file = "SQLAlchemy-1.4.49-cp39-cp39-win_amd64.whl", hash = "sha256:bbdf16372859b8ed3f4d05f925a984771cd2abd18bd187042f24be4886c2a15f"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:af66001d7b76a3fab0d5e4c1ec9339ac45748bc4a399cbc2baa48c1980d3c1f4"},
{file = "SQLAlchemy-1.4.49.tar.gz", hash = "sha256:06ff25cbae30c396c4b7737464f2a7fc37a67b7da409993b182b024cec80aed9"}, {file = "SQLAlchemy-2.0.22-cp38-cp38-win32.whl", hash = "sha256:9e55dff5ec115316dd7a083cdc1a52de63693695aecf72bc53a8e1468ce429e5"},
{file = "SQLAlchemy-2.0.22-cp38-cp38-win_amd64.whl", hash = "sha256:4e869a8ff7ee7a833b74868a0887e8462445ec462432d8cbeff5e85f475186da"},
{file = "SQLAlchemy-2.0.22-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9886a72c8e6371280cb247c5d32c9c8fa141dc560124348762db8a8b236f8692"},
{file = "SQLAlchemy-2.0.22-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a571bc8ac092a3175a1d994794a8e7a1f2f651e7c744de24a19b4f740fe95034"},
{file = "SQLAlchemy-2.0.22-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8db5ba8b7da759b727faebc4289a9e6a51edadc7fc32207a30f7c6203a181592"},
{file = "SQLAlchemy-2.0.22-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b0b3f2686c3f162123adba3cb8b626ed7e9b8433ab528e36ed270b4f70d1cdb"},
{file = "SQLAlchemy-2.0.22-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0c1fea8c0abcb070ffe15311853abfda4e55bf7dc1d4889497b3403629f3bf00"},
{file = "SQLAlchemy-2.0.22-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4bb062784f37b2d75fd9b074c8ec360ad5df71f933f927e9e95c50eb8e05323c"},
{file = "SQLAlchemy-2.0.22-cp39-cp39-win32.whl", hash = "sha256:58a3aba1bfb32ae7af68da3f277ed91d9f57620cf7ce651db96636790a78b736"},
{file = "SQLAlchemy-2.0.22-cp39-cp39-win_amd64.whl", hash = "sha256:92e512a6af769e4725fa5b25981ba790335d42c5977e94ded07db7d641490a85"},
{file = "SQLAlchemy-2.0.22-py3-none-any.whl", hash = "sha256:3076740335e4aaadd7deb3fe6dcb96b3015f1613bd190a4e1634e1b99b02ec86"},
{file = "SQLAlchemy-2.0.22.tar.gz", hash = "sha256:5434cc601aa17570d79e5377f5fd45ff92f9379e2abed0be5e8c2fba8d353d2b"},
] ]
[package.dependencies] [package.dependencies]
greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} greenlet = {version = "!=0.4.17", markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""}
typing-extensions = ">=4.2.0"
[package.extras] [package.extras]
aiomysql = ["aiomysql", "greenlet (!=0.4.17)"] aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"] aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing-extensions (!=3.10.0.1)"]
asyncio = ["greenlet (!=0.4.17)"] asyncio = ["greenlet (!=0.4.17)"]
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"] asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (!=0.4.17)"]
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)"] mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5)"]
mssql = ["pyodbc"] mssql = ["pyodbc"]
mssql-pymssql = ["pymssql"] mssql-pymssql = ["pymssql"]
mssql-pyodbc = ["pyodbc"] mssql-pyodbc = ["pyodbc"]
mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"] mypy = ["mypy (>=0.910)"]
mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"] mysql = ["mysqlclient (>=1.4.0)"]
mysql-connector = ["mysql-connector-python"] mysql-connector = ["mysql-connector-python"]
oracle = ["cx-oracle (>=7)", "cx-oracle (>=7,<8)"] oracle = ["cx-oracle (>=7)"]
oracle-oracledb = ["oracledb (>=1.0.1)"]
postgresql = ["psycopg2 (>=2.7)"] postgresql = ["psycopg2 (>=2.7)"]
postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"] postgresql-asyncpg = ["asyncpg", "greenlet (!=0.4.17)"]
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)"] postgresql-pg8000 = ["pg8000 (>=1.29.1)"]
postgresql-psycopg = ["psycopg (>=3.0.7)"]
postgresql-psycopg2binary = ["psycopg2-binary"] postgresql-psycopg2binary = ["psycopg2-binary"]
postgresql-psycopg2cffi = ["psycopg2cffi"] postgresql-psycopg2cffi = ["psycopg2cffi"]
pymysql = ["pymysql", "pymysql (<1)"] postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"]
pymysql = ["pymysql"]
sqlcipher = ["sqlcipher3-binary"] sqlcipher = ["sqlcipher3-binary"]
[[package]] [[package]]
@ -1965,4 +1970,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = ">=3.9,<3.12" python-versions = ">=3.9,<3.12"
content-hash = "87954b20049b8c138bd6c7767247aa017a8c5c64cc857a12ab9d78cf8ac787c7" content-hash = "cfdf70424a62418aa4c3b233cb5ab2486415364bf5ef27198db1f07a579927c7"

View file

@ -83,7 +83,7 @@ Authlib = "^1.2.1"
Jinja2 = "^3.1.2" Jinja2 = "^3.1.2"
Markdown = "^3.4.4" Markdown = "^3.4.4"
Werkzeug = "^3.0.0" Werkzeug = "^3.0.0"
SQLAlchemy = "^1.4.49" SQLAlchemy = "^2.0.22"
# ASGI # ASGI
uvicorn = "^0.23.0" uvicorn = "^0.23.0"

View file

@ -43,7 +43,7 @@ from multiprocessing import Lock
import py import py
import pytest import pytest
from sqlalchemy import create_engine from sqlalchemy import create_engine, text
from sqlalchemy.engine import URL from sqlalchemy.engine import URL
from sqlalchemy.engine.base import Engine from sqlalchemy.engine.base import Engine
from sqlalchemy.exc import ProgrammingError from sqlalchemy.exc import ProgrammingError
@ -104,15 +104,16 @@ def _create_database(engine: Engine, dbname: str) -> None:
:param dbname: Database name to create :param dbname: Database name to create
""" """
conn = engine.connect() conn = engine.connect()
try: with conn.begin():
conn.execute(f"CREATE DATABASE {dbname}") try:
except ProgrammingError: # pragma: no cover conn.execute(text(f"CREATE DATABASE {dbname}"))
# The database most likely already existed if we hit except ProgrammingError: # pragma: no cover
# a ProgrammingError. Just drop the database and try # The database most likely already existed if we hit
# again. If at that point things still fail, any # a ProgrammingError. Just drop the database and try
# exception will be propogated up to the caller. # again. If at that point things still fail, any
conn.execute(f"DROP DATABASE {dbname}") # exception will be propogated up to the caller.
conn.execute(f"CREATE DATABASE {dbname}") conn.execute(text(f"DROP DATABASE {dbname}"))
conn.execute(text(f"CREATE DATABASE {dbname}"))
conn.close() conn.close()
initdb.run(AlembicArgs) initdb.run(AlembicArgs)
@ -124,9 +125,10 @@ def _drop_database(engine: Engine, dbname: str) -> None:
:param engine: Engine returned by test_engine() :param engine: Engine returned by test_engine()
:param dbname: Database name to drop :param dbname: Database name to drop
""" """
aurweb.schema.metadata.drop_all(bind=engine) # aurweb.schema.metadata.drop_all(bind=engine)
conn = engine.connect() conn = engine.connect()
conn.execute(f"DROP DATABASE {dbname}") with conn.begin():
conn.execute(text(f"DROP DATABASE {dbname}"))
conn.close() conn.close()

View file

@ -830,6 +830,7 @@ def test_post_account_edit_type_as_dev(client: TestClient, pm_user: User):
request.cookies = cookies request.cookies = cookies
resp = request.post(endpoint, data=data) resp = request.post(endpoint, data=data)
assert resp.status_code == int(HTTPStatus.OK) assert resp.status_code == int(HTTPStatus.OK)
db.refresh(user2)
assert user2.AccountTypeID == at.DEVELOPER_ID assert user2.AccountTypeID == at.DEVELOPER_ID
@ -850,6 +851,7 @@ def test_post_account_edit_invalid_type_as_pm(client: TestClient, pm_user: User)
request.cookies = cookies request.cookies = cookies
resp = request.post(endpoint, data=data) resp = request.post(endpoint, data=data)
assert resp.status_code == int(HTTPStatus.BAD_REQUEST) assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
db.refresh(user2)
assert user2.AccountTypeID == at.USER_ID assert user2.AccountTypeID == at.USER_ID
errors = get_errors(resp.text) errors = get_errors(resp.text)
@ -1020,6 +1022,7 @@ def test_post_account_edit_inactivity(client: TestClient, user: User):
assert resp.status_code == int(HTTPStatus.OK) assert resp.status_code == int(HTTPStatus.OK)
# Make sure the user record got updated correctly. # Make sure the user record got updated correctly.
db.refresh(user)
assert user.InactivityTS > 0 assert user.InactivityTS > 0
post_data.update({"J": False}) post_data.update({"J": False})
@ -1028,6 +1031,7 @@ def test_post_account_edit_inactivity(client: TestClient, user: User):
resp = request.post(f"/account/{user.Username}/edit", data=post_data) resp = request.post(f"/account/{user.Username}/edit", data=post_data)
assert resp.status_code == int(HTTPStatus.OK) assert resp.status_code == int(HTTPStatus.OK)
db.refresh(user)
assert user.InactivityTS == 0 assert user.InactivityTS == 0
@ -1050,6 +1054,7 @@ def test_post_account_edit_suspended(client: TestClient, user: User):
assert resp.status_code == int(HTTPStatus.OK) assert resp.status_code == int(HTTPStatus.OK)
# Make sure the user record got updated correctly. # Make sure the user record got updated correctly.
db.refresh(user)
assert user.Suspended assert user.Suspended
# Let's make sure the DB got updated properly. # Let's make sure the DB got updated properly.
assert user.session is None assert user.session is None
@ -1207,6 +1212,7 @@ def test_post_account_edit_password(client: TestClient, user: User):
assert response.status_code == int(HTTPStatus.OK) assert response.status_code == int(HTTPStatus.OK)
db.refresh(user)
assert user.valid_password("newPassword") assert user.valid_password("newPassword")
@ -1273,6 +1279,7 @@ def test_post_account_edit_self_type_as_pm(client: TestClient, pm_user: User):
resp = request.post(endpoint, data=data) resp = request.post(endpoint, data=data)
assert resp.status_code == int(HTTPStatus.OK) assert resp.status_code == int(HTTPStatus.OK)
db.refresh(pm_user)
assert pm_user.AccountTypeID == USER_ID assert pm_user.AccountTypeID == USER_ID
@ -1308,6 +1315,7 @@ def test_post_account_edit_other_user_type_as_pm(
assert resp.status_code == int(HTTPStatus.OK) assert resp.status_code == int(HTTPStatus.OK)
# Let's make sure the DB got updated properly. # Let's make sure the DB got updated properly.
db.refresh(user2)
assert user2.AccountTypeID == PACKAGE_MAINTAINER_ID assert user2.AccountTypeID == PACKAGE_MAINTAINER_ID
# and also that this got logged out at DEBUG level. # and also that this got logged out at DEBUG level.

View file

@ -24,5 +24,6 @@ def test_run():
aurweb.initdb.run(Args()) aurweb.initdb.run(Args())
# Check that constant table rows got added via initdb. # Check that constant table rows got added via initdb.
record = aurweb.db.query(AccountType, AccountType.AccountType == "User").first() with aurweb.db.begin():
record = aurweb.db.query(AccountType, AccountType.AccountType == "User").first()
assert record is not None assert record is not None

View file

@ -768,6 +768,7 @@ def test_pm_proposal_vote(client, proposal):
assert response.status_code == int(HTTPStatus.OK) assert response.status_code == int(HTTPStatus.OK)
# Check that the proposal record got updated. # Check that the proposal record got updated.
db.refresh(voteinfo)
assert voteinfo.Yes == yes + 1 assert voteinfo.Yes == yes + 1
# Check that the new PMVote exists. # Check that the new PMVote exists.

View file

@ -1528,6 +1528,7 @@ def test_packages_post_disown_as_maintainer(
errors = get_errors(resp.text) errors = get_errors(resp.text)
expected = "You did not select any packages to disown." expected = "You did not select any packages to disown."
assert errors[0].text.strip() == expected assert errors[0].text.strip() == expected
db.refresh(package)
assert package.PackageBase.Maintainer is not None assert package.PackageBase.Maintainer is not None
# Try to disown `package` without giving the confirm argument. # Try to disown `package` without giving the confirm argument.
@ -1552,6 +1553,7 @@ def test_packages_post_disown_as_maintainer(
data={"action": "disown", "IDs": [package.ID], "confirm": True}, data={"action": "disown", "IDs": [package.ID], "confirm": True},
) )
assert resp.status_code == int(HTTPStatus.BAD_REQUEST) assert resp.status_code == int(HTTPStatus.BAD_REQUEST)
db.refresh(package)
assert package.PackageBase.Maintainer is not None assert package.PackageBase.Maintainer is not None
errors = get_errors(resp.text) errors = get_errors(resp.text)
expected = "You are not allowed to disown one of the packages you selected." expected = "You are not allowed to disown one of the packages you selected."
@ -1565,6 +1567,7 @@ def test_packages_post_disown_as_maintainer(
data={"action": "disown", "IDs": [package.ID], "confirm": True}, data={"action": "disown", "IDs": [package.ID], "confirm": True},
) )
db.get_session().expire_all()
assert package.PackageBase.Maintainer is None assert package.PackageBase.Maintainer is None
successes = get_successes(resp.text) successes = get_successes(resp.text)
expected = "The selected packages have been disowned." expected = "The selected packages have been disowned."
@ -1649,6 +1652,7 @@ def test_packages_post_delete(
# Whoo. Now, let's finally make a valid request as `pm_user` # Whoo. Now, let's finally make a valid request as `pm_user`
# to delete `package`. # to delete `package`.
pkgname = package.PackageBase.Name
with client as request: with client as request:
request.cookies = pm_cookies request.cookies = pm_cookies
resp = request.post( resp = request.post(
@ -1661,7 +1665,7 @@ def test_packages_post_delete(
assert successes[0].text.strip() == expected assert successes[0].text.strip() == expected
# Expect that the package deletion was logged. # Expect that the package deletion was logged.
pkgbases = [package.PackageBase.Name] pkgbases = [pkgname]
expected = ( expected = (
f"Privileged user '{pm_user.Username}' deleted the " f"Privileged user '{pm_user.Username}' deleted the "
f"following package bases: {str(pkgbases)}." f"following package bases: {str(pkgbases)}."

View file

@ -688,6 +688,7 @@ def test_pkgbase_comment_pin_as_co(
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# Assert that PinnedTS got set. # Assert that PinnedTS got set.
db.refresh(comment)
assert comment.PinnedTS > 0 assert comment.PinnedTS > 0
# Unpin the comment we just pinned. # Unpin the comment we just pinned.
@ -698,6 +699,7 @@ def test_pkgbase_comment_pin_as_co(
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# Let's assert that PinnedTS was unset. # Let's assert that PinnedTS was unset.
db.refresh(comment)
assert comment.PinnedTS == 0 assert comment.PinnedTS == 0
@ -716,6 +718,7 @@ def test_pkgbase_comment_pin(
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# Assert that PinnedTS got set. # Assert that PinnedTS got set.
db.refresh(comment)
assert comment.PinnedTS > 0 assert comment.PinnedTS > 0
# Unpin the comment we just pinned. # Unpin the comment we just pinned.
@ -726,6 +729,7 @@ def test_pkgbase_comment_pin(
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# Let's assert that PinnedTS was unset. # Let's assert that PinnedTS was unset.
db.refresh(comment)
assert comment.PinnedTS == 0 assert comment.PinnedTS == 0
@ -1040,6 +1044,7 @@ def test_pkgbase_flag(
request.cookies = cookies request.cookies = cookies
resp = request.post(endpoint, data={"comments": "Test"}) resp = request.post(endpoint, data={"comments": "Test"})
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
db.refresh(pkgbase)
assert pkgbase.Flagger == user assert pkgbase.Flagger == user
assert pkgbase.FlaggerComment == "Test" assert pkgbase.FlaggerComment == "Test"
@ -1077,6 +1082,7 @@ def test_pkgbase_flag(
request.cookies = user2_cookies request.cookies = user2_cookies
resp = request.post(endpoint) resp = request.post(endpoint)
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
db.refresh(pkgbase)
assert pkgbase.Flagger == user assert pkgbase.Flagger == user
# Now, test that the 'maintainer' user can. # Now, test that the 'maintainer' user can.
@ -1085,6 +1091,7 @@ def test_pkgbase_flag(
request.cookies = maint_cookies request.cookies = maint_cookies
resp = request.post(endpoint) resp = request.post(endpoint)
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
db.refresh(pkgbase)
assert pkgbase.Flagger is None assert pkgbase.Flagger is None
# Flag it again. # Flag it again.
@ -1098,6 +1105,7 @@ def test_pkgbase_flag(
request.cookies = cookies request.cookies = cookies
resp = request.post(endpoint) resp = request.post(endpoint)
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
db.refresh(pkgbase)
assert pkgbase.Flagger is None assert pkgbase.Flagger is None
@ -1170,6 +1178,7 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package):
vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first()
assert vote is not None assert vote is not None
db.refresh(pkgbase)
assert pkgbase.NumVotes == 1 assert pkgbase.NumVotes == 1
# Remove vote. # Remove vote.
@ -1181,6 +1190,7 @@ def test_pkgbase_vote(client: TestClient, user: User, package: Package):
vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first() vote = pkgbase.package_votes.filter(PackageVote.UsersID == user.ID).first()
assert vote is None assert vote is None
db.refresh(pkgbase)
assert pkgbase.NumVotes == 0 assert pkgbase.NumVotes == 0
@ -1592,9 +1602,9 @@ def test_pkgbase_merge_post(
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
# Save these relationships for later comparison. # Save these relationships for later comparison.
comments = package.PackageBase.comments.all() comments = [row.__dict__ for row in package.PackageBase.comments.all()]
notifs = package.PackageBase.notifications.all() notifs = [row.__dict__ for row in package.PackageBase.notifications.all()]
votes = package.PackageBase.package_votes.all() votes = [row.__dict__ for row in package.PackageBase.package_votes.all()]
# Merge the package into target. # Merge the package into target.
endpoint = f"/pkgbase/{package.PackageBase.Name}/merge" endpoint = f"/pkgbase/{package.PackageBase.Name}/merge"
@ -1612,9 +1622,13 @@ def test_pkgbase_merge_post(
# Assert that the original comments, notifs and votes we setup # Assert that the original comments, notifs and votes we setup
# got migrated to target as intended. # got migrated to target as intended.
assert comments == target.comments.all() db.get_session().refresh(target)
assert notifs == target.notifications.all() assert len(comments) == target.comments.count()
assert votes == target.package_votes.all() assert comments[0]["PackageBaseID"] != target.ID
assert len(notifs) == target.notifications.count()
assert notifs[0]["PackageBaseID"] != target.ID
assert len(votes) == target.package_votes.count()
assert votes[0]["PackageBaseID"] != target.ID
# ...and that the package got deleted. # ...and that the package got deleted.
package = db.query(Package).filter(Package.Name == pkgname).first() package = db.query(Package).filter(Package.Name == pkgname).first()

View file

@ -649,6 +649,7 @@ def test_orphan_request(
assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}" assert resp.headers.get("location") == f"/pkgbase/{pkgbase.Name}"
# We should have unset the maintainer. # We should have unset the maintainer.
db.refresh(pkgbase)
assert pkgbase.Maintainer is None assert pkgbase.Maintainer is None
# We should have removed the comaintainers. # We should have removed the comaintainers.
@ -748,6 +749,7 @@ def test_orphan_as_maintainer(client: TestClient, auser: User, pkgbase: PackageB
# As the pkgbase maintainer, disowning the package just ends up # As the pkgbase maintainer, disowning the package just ends up
# either promoting the lowest priority comaintainer or removing # either promoting the lowest priority comaintainer or removing
# the associated maintainer relationship altogether. # the associated maintainer relationship altogether.
db.refresh(pkgbase)
assert pkgbase.Maintainer is None assert pkgbase.Maintainer is None
@ -1044,6 +1046,7 @@ def test_requests_close_post(client: TestClient, user: User, pkgreq: PackageRequ
resp = request.post(f"/requests/{pkgreq.ID}/close") resp = request.post(f"/requests/{pkgreq.ID}/close")
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
db.refresh(pkgreq)
assert pkgreq.Status == REJECTED_ID assert pkgreq.Status == REJECTED_ID
assert pkgreq.Closer == user assert pkgreq.Closer == user
assert pkgreq.ClosureComment == str() assert pkgreq.ClosureComment == str()
@ -1060,6 +1063,7 @@ def test_requests_close_post_rejected(
) )
assert resp.status_code == int(HTTPStatus.SEE_OTHER) assert resp.status_code == int(HTTPStatus.SEE_OTHER)
db.refresh(pkgreq)
assert pkgreq.Status == REJECTED_ID assert pkgreq.Status == REJECTED_ID
assert pkgreq.Closer == user assert pkgreq.Closer == user
assert pkgreq.ClosureComment == str() assert pkgreq.ClosureComment == str()

View file

@ -102,6 +102,7 @@ def test_user_language(client: TestClient, user: User):
req.cookies = {"AURSID": sid} req.cookies = {"AURSID": sid}
response = req.post("/language", data=post_data) response = req.post("/language", data=post_data)
assert response.status_code == int(HTTPStatus.SEE_OTHER) assert response.status_code == int(HTTPStatus.SEE_OTHER)
db.refresh(user)
assert user.LangPreference == "de" assert user.LangPreference == "de"

View file

@ -1,5 +1,5 @@
import pytest import pytest
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError, SAWarning
from aurweb import db, time from aurweb import db, time
from aurweb.db import create, rollback from aurweb.db import create, rollback
@ -109,7 +109,7 @@ def test_voteinfo_null_submitter_raises(user: User):
def test_voteinfo_null_agenda_raises(user: User): def test_voteinfo_null_agenda_raises(user: User):
with pytest.raises(IntegrityError): with pytest.raises(IntegrityError), pytest.warns(SAWarning):
with db.begin(): with db.begin():
create( create(
VoteInfo, VoteInfo,
@ -123,7 +123,7 @@ def test_voteinfo_null_agenda_raises(user: User):
def test_voteinfo_null_user_raises(user: User): def test_voteinfo_null_user_raises(user: User):
with pytest.raises(IntegrityError): with pytest.raises(IntegrityError), pytest.warns(SAWarning):
with db.begin(): with db.begin():
create( create(
VoteInfo, VoteInfo,
@ -137,7 +137,7 @@ def test_voteinfo_null_user_raises(user: User):
def test_voteinfo_null_submitted_raises(user: User): def test_voteinfo_null_submitted_raises(user: User):
with pytest.raises(IntegrityError): with pytest.raises(IntegrityError), pytest.warns(SAWarning):
with db.begin(): with db.begin():
create( create(
VoteInfo, VoteInfo,
@ -151,7 +151,7 @@ def test_voteinfo_null_submitted_raises(user: User):
def test_voteinfo_null_end_raises(user: User): def test_voteinfo_null_end_raises(user: User):
with pytest.raises(IntegrityError): with pytest.raises(IntegrityError), pytest.warns(SAWarning):
with db.begin(): with db.begin():
create( create(
VoteInfo, VoteInfo,