Playing with asyncio and context managers
This commit is contained in:
parent
1f067d71d7
commit
73d92645ca
7 changed files with 207 additions and 25 deletions
0
dbapi/context_managers.py
Normal file
0
dbapi/context_managers.py
Normal file
15
dbapi/migrator.py
Normal file
15
dbapi/migrator.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine
|
||||||
|
from dbapi.tables import metadata_obj
|
||||||
|
|
||||||
|
|
||||||
|
class FitnessDatabseMigrator:
|
||||||
|
"""Class for performing management operations with database"""
|
||||||
|
|
||||||
|
def __init__(self, async_engine: AsyncEngine) -> None:
|
||||||
|
self.engine = async_engine
|
||||||
|
|
||||||
|
async def reset_database(self):
|
||||||
|
"""Method for dropping all tables and create them from tables metadata"""
|
||||||
|
async with self.engine.begin() as conn:
|
||||||
|
await conn.run_sync(metadata_obj.drop_all)
|
||||||
|
await conn.run_sync(metadata_obj.create_all)
|
66
main.py
66
main.py
|
@ -1,10 +1,17 @@
|
||||||
|
import asyncio
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
import os
|
import os
|
||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
from sqlalchemy import Table, create_engine, text, insert
|
from sqlalchemy import Table, create_engine, text, insert
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from dbapi.repositories import ApproachRepository, ExerciseRepository, TrainingRepository
|
from sqlalchemy.ext.asyncio import create_async_engine
|
||||||
|
from dbapi.migrator import FitnessDatabseMigrator
|
||||||
|
from dbapi.repositories import (
|
||||||
|
ApproachRepository,
|
||||||
|
ExerciseRepository,
|
||||||
|
TrainingRepository,
|
||||||
|
)
|
||||||
from dbapi.tables import metadata_obj, training, exercise, approach
|
from dbapi.tables import metadata_obj, training, exercise, approach
|
||||||
from obsidian.notes_parser import parse_training_data, remap_unique_exercises
|
from obsidian.notes_parser import parse_training_data, remap_unique_exercises
|
||||||
from apple.notes_parser import parse_training_data as apple_parse_training_data
|
from apple.notes_parser import parse_training_data as apple_parse_training_data
|
||||||
|
@ -22,6 +29,13 @@ engine = create_engine(
|
||||||
echo=True,
|
echo=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Creating async engine for Database connection
|
||||||
|
async_engine = create_async_engine(
|
||||||
|
f"postgresql+asyncpg://{DB_USERNAME}:{DB_PASS}@localhost:5433/fitness_database",
|
||||||
|
echo=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# NOTE: "Begin once" style - using `.begin` as context creator for SQLAlchemy
|
# NOTE: "Begin once" style - using `.begin` as context creator for SQLAlchemy
|
||||||
# with engine.begin() as conn:
|
# with engine.begin() as conn:
|
||||||
# result = conn.execute(text("select 'hello world'"))
|
# result = conn.execute(text("select 'hello world'"))
|
||||||
|
@ -44,8 +58,8 @@ engine = create_engine(
|
||||||
# TODO: Check how migrations are done
|
# TODO: Check how migrations are done
|
||||||
|
|
||||||
# NOTE: Drop all Tables from database
|
# NOTE: Drop all Tables from database
|
||||||
metadata_obj.drop_all(engine)
|
# metadata_obj.drop_all(engine)
|
||||||
metadata_obj.create_all(engine)
|
# metadata_obj.create_all(engine)
|
||||||
|
|
||||||
# NOTE: Table reflection - generating table object from existing tables (only tables, that are stored in metadata)
|
# NOTE: Table reflection - generating table object from existing tables (only tables, that are stored in metadata)
|
||||||
# some_table = Table("some_table", metadata_obj, autoload_with=engine)
|
# some_table = Table("some_table", metadata_obj, autoload_with=engine)
|
||||||
|
@ -55,27 +69,27 @@ metadata_obj.create_all(engine)
|
||||||
|
|
||||||
# Inserting training values into database
|
# Inserting training values into database
|
||||||
|
|
||||||
trainings: List[Training] = parse_training_data()
|
# trainings: List[Training] = parse_training_data()
|
||||||
for train in trainings:
|
# for train in trainings:
|
||||||
if not train:
|
# if not train:
|
||||||
continue
|
# continue
|
||||||
else:
|
# else:
|
||||||
print(train)
|
# print(train)
|
||||||
new_training_pk: int = TrainingRepository(engine).create_training(train.date)
|
# new_training_pk: int = TrainingRepository(engine).create_training(train.date)
|
||||||
for exr in train.exercises:
|
# for exr in train.exercises:
|
||||||
approach_statements = []
|
# approach_statements = []
|
||||||
new_exercise_pk: int = ExerciseRepository(engine).create_exercise(
|
# new_exercise_pk: int = ExerciseRepository(engine).create_exercise(
|
||||||
training_pk=new_training_pk, exercise_name=exr.name
|
# training_pk=new_training_pk, exercise_name=exr.name
|
||||||
)
|
# )
|
||||||
for appr in exr.approaches:
|
# for appr in exr.approaches:
|
||||||
new_approach_pk: int = ApproachRepository(engine).create_approach(
|
# new_approach_pk: int = ApproachRepository(engine).create_approach(
|
||||||
exercise_pk=new_exercise_pk, weight=appr.weight, reps=appr.reps
|
# exercise_pk=new_exercise_pk, weight=appr.weight, reps=appr.reps
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
|
#
|
||||||
print("-------------------------\n" * 2)
|
# print("-------------------------\n" * 2)
|
||||||
print("-------------------------\n" * 2)
|
# print("-------------------------\n" * 2)
|
||||||
ExerciseRepository(engine=engine).get_exercises_from_training(1)
|
# ExerciseRepository(engine=engine).get_exercises_from_training(1)
|
||||||
# -----
|
# -----
|
||||||
|
|
||||||
# Calculating unique exercises for obsidian
|
# Calculating unique exercises for obsidian
|
||||||
|
@ -170,3 +184,7 @@ ExerciseRepository(engine=engine).get_exercises_from_training(1)
|
||||||
# unique_exercise_parsed_names[exr.name] += 1
|
# unique_exercise_parsed_names[exr.name] += 1
|
||||||
# pprint(unique_exercise_parsed_names)
|
# pprint(unique_exercise_parsed_names)
|
||||||
# print(len(combined_trainings))
|
# print(len(combined_trainings))
|
||||||
|
|
||||||
|
fbm = FitnessDatabseMigrator(async_engine=async_engine)
|
||||||
|
|
||||||
|
asyncio.run(fbm.reset_database())
|
||||||
|
|
3
playground/README.md
Normal file
3
playground/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Directory for testing hypotheses
|
||||||
|
## context.py
|
||||||
|
File for testing context operations
|
66
playground/contexts.py
Normal file
66
playground/contexts.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
class ContextPlayground:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.keka = "Hi, i am keka"
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
print("Entered context")
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
if exc_type:
|
||||||
|
print(f"\tException raised. Type: {exc_type}")
|
||||||
|
if exc_val:
|
||||||
|
print(f"\tException raised. Value: {exc_val}")
|
||||||
|
if exc_tb:
|
||||||
|
print(f"\tException raised. Traceback: {exc_tb}")
|
||||||
|
print("\tExiting context")
|
||||||
|
# Returning True means that context manager will supress the exception and it will not be propagated outside
|
||||||
|
# the with block. IOW it indicated, that exception is going to be handled inside context
|
||||||
|
return True
|
||||||
|
# Returning False means that the exception will be propagated and it will be raised outside the with block
|
||||||
|
# IOW it means that the exception will not be handled inside context manager and must be handled by the caller
|
||||||
|
# Note from documentation: __exit__() methods should not reraise the passed-in exception;
|
||||||
|
# this is the caller’s responsibility.
|
||||||
|
# return False # Or return None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
with ContextPlayground() as kek:
|
||||||
|
print(f"\t\t{kek.keka}")
|
||||||
|
print("\t\tInside context")
|
||||||
|
|
||||||
|
print("Outside context")
|
||||||
|
|
||||||
|
class AsyncContextPlayground:
|
||||||
|
"""Asyncio version of ContextPlayground"""
|
||||||
|
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.keka = "Hi, i am async Keka"
|
||||||
|
|
||||||
|
async def __aenter__(self) -> None:
|
||||||
|
print("\tEntered async context")
|
||||||
|
return self
|
||||||
|
|
||||||
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
||||||
|
if exc_type:
|
||||||
|
print(f"\t\tException raised. Type: {exc_type}")
|
||||||
|
if exc_val:
|
||||||
|
print(f"\t\tException raised. Value: {exc_val}")
|
||||||
|
if exc_tb:
|
||||||
|
print(f"\t\tException raised. Traceback: {exc_tb}")
|
||||||
|
print("\tExiting async context")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_main():
|
||||||
|
async with AsyncContextPlayground() as kek:
|
||||||
|
print(f"\t\t{kek.keka}")
|
||||||
|
print("\t\tInside async context")
|
||||||
|
raise ValueError("An error occurred") # Uncomment to test exception handling
|
||||||
|
|
||||||
|
print("Outside async context")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(async_main())
|
||||||
|
|
81
poetry.lock
generated
81
poetry.lock
generated
|
@ -12,6 +12,85 @@ files = [
|
||||||
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
|
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-timeout"
|
||||||
|
version = "5.0.1"
|
||||||
|
description = "Timeout context manager for asyncio programs"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"},
|
||||||
|
{file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "asyncpg"
|
||||||
|
version = "0.30.0"
|
||||||
|
description = "An asyncio PostgreSQL driver"
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8.0"
|
||||||
|
files = [
|
||||||
|
{file = "asyncpg-0.30.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfb4dd5ae0699bad2b233672c8fc5ccbd9ad24b89afded02341786887e37927e"},
|
||||||
|
{file = "asyncpg-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc1f62c792752a49f88b7e6f774c26077091b44caceb1983509edc18a2222ec0"},
|
||||||
|
{file = "asyncpg-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3152fef2e265c9c24eec4ee3d22b4f4d2703d30614b0b6753e9ed4115c8a146f"},
|
||||||
|
{file = "asyncpg-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7255812ac85099a0e1ffb81b10dc477b9973345793776b128a23e60148dd1af"},
|
||||||
|
{file = "asyncpg-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:578445f09f45d1ad7abddbff2a3c7f7c291738fdae0abffbeb737d3fc3ab8b75"},
|
||||||
|
{file = "asyncpg-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c42f6bb65a277ce4d93f3fba46b91a265631c8df7250592dd4f11f8b0152150f"},
|
||||||
|
{file = "asyncpg-0.30.0-cp310-cp310-win32.whl", hash = "sha256:aa403147d3e07a267ada2ae34dfc9324e67ccc4cdca35261c8c22792ba2b10cf"},
|
||||||
|
{file = "asyncpg-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb622c94db4e13137c4c7f98834185049cc50ee01d8f657ef898b6407c7b9c50"},
|
||||||
|
{file = "asyncpg-0.30.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5e0511ad3dec5f6b4f7a9e063591d407eee66b88c14e2ea636f187da1dcfff6a"},
|
||||||
|
{file = "asyncpg-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:915aeb9f79316b43c3207363af12d0e6fd10776641a7de8a01212afd95bdf0ed"},
|
||||||
|
{file = "asyncpg-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c198a00cce9506fcd0bf219a799f38ac7a237745e1d27f0e1f66d3707c84a5a"},
|
||||||
|
{file = "asyncpg-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3326e6d7381799e9735ca2ec9fd7be4d5fef5dcbc3cb555d8a463d8460607956"},
|
||||||
|
{file = "asyncpg-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:51da377487e249e35bd0859661f6ee2b81db11ad1f4fc036194bc9cb2ead5056"},
|
||||||
|
{file = "asyncpg-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc6d84136f9c4d24d358f3b02be4b6ba358abd09f80737d1ac7c444f36108454"},
|
||||||
|
{file = "asyncpg-0.30.0-cp311-cp311-win32.whl", hash = "sha256:574156480df14f64c2d76450a3f3aaaf26105869cad3865041156b38459e935d"},
|
||||||
|
{file = "asyncpg-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:3356637f0bd830407b5597317b3cb3571387ae52ddc3bca6233682be88bbbc1f"},
|
||||||
|
{file = "asyncpg-0.30.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c902a60b52e506d38d7e80e0dd5399f657220f24635fee368117b8b5fce1142e"},
|
||||||
|
{file = "asyncpg-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aca1548e43bbb9f0f627a04666fedaca23db0a31a84136ad1f868cb15deb6e3a"},
|
||||||
|
{file = "asyncpg-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c2a2ef565400234a633da0eafdce27e843836256d40705d83ab7ec42074efb3"},
|
||||||
|
{file = "asyncpg-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1292b84ee06ac8a2ad8e51c7475aa309245874b61333d97411aab835c4a2f737"},
|
||||||
|
{file = "asyncpg-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0f5712350388d0cd0615caec629ad53c81e506b1abaaf8d14c93f54b35e3595a"},
|
||||||
|
{file = "asyncpg-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:db9891e2d76e6f425746c5d2da01921e9a16b5a71a1c905b13f30e12a257c4af"},
|
||||||
|
{file = "asyncpg-0.30.0-cp312-cp312-win32.whl", hash = "sha256:68d71a1be3d83d0570049cd1654a9bdfe506e794ecc98ad0873304a9f35e411e"},
|
||||||
|
{file = "asyncpg-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:9a0292c6af5c500523949155ec17b7fe01a00ace33b68a476d6b5059f9630305"},
|
||||||
|
{file = "asyncpg-0.30.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05b185ebb8083c8568ea8a40e896d5f7af4b8554b64d7719c0eaa1eb5a5c3a70"},
|
||||||
|
{file = "asyncpg-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c47806b1a8cbb0a0db896f4cd34d89942effe353a5035c62734ab13b9f938da3"},
|
||||||
|
{file = "asyncpg-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b6fde867a74e8c76c71e2f64f80c64c0f3163e687f1763cfaf21633ec24ec33"},
|
||||||
|
{file = "asyncpg-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46973045b567972128a27d40001124fbc821c87a6cade040cfcd4fa8a30bcdc4"},
|
||||||
|
{file = "asyncpg-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9110df111cabc2ed81aad2f35394a00cadf4f2e0635603db6ebbd0fc896f46a4"},
|
||||||
|
{file = "asyncpg-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04ff0785ae7eed6cc138e73fc67b8e51d54ee7a3ce9b63666ce55a0bf095f7ba"},
|
||||||
|
{file = "asyncpg-0.30.0-cp313-cp313-win32.whl", hash = "sha256:ae374585f51c2b444510cdf3595b97ece4f233fde739aa14b50e0d64e8a7a590"},
|
||||||
|
{file = "asyncpg-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:f59b430b8e27557c3fb9869222559f7417ced18688375825f8f12302c34e915e"},
|
||||||
|
{file = "asyncpg-0.30.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:29ff1fc8b5bf724273782ff8b4f57b0f8220a1b2324184846b39d1ab4122031d"},
|
||||||
|
{file = "asyncpg-0.30.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64e899bce0600871b55368b8483e5e3e7f1860c9482e7f12e0a771e747988168"},
|
||||||
|
{file = "asyncpg-0.30.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b290f4726a887f75dcd1b3006f484252db37602313f806e9ffc4e5996cfe5cb"},
|
||||||
|
{file = "asyncpg-0.30.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f86b0e2cd3f1249d6fe6fd6cfe0cd4538ba994e2d8249c0491925629b9104d0f"},
|
||||||
|
{file = "asyncpg-0.30.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:393af4e3214c8fa4c7b86da6364384c0d1b3298d45803375572f415b6f673f38"},
|
||||||
|
{file = "asyncpg-0.30.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fd4406d09208d5b4a14db9a9dbb311b6d7aeeab57bded7ed2f8ea41aeef39b34"},
|
||||||
|
{file = "asyncpg-0.30.0-cp38-cp38-win32.whl", hash = "sha256:0b448f0150e1c3b96cb0438a0d0aa4871f1472e58de14a3ec320dbb2798fb0d4"},
|
||||||
|
{file = "asyncpg-0.30.0-cp38-cp38-win_amd64.whl", hash = "sha256:f23b836dd90bea21104f69547923a02b167d999ce053f3d502081acea2fba15b"},
|
||||||
|
{file = "asyncpg-0.30.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f4e83f067b35ab5e6371f8a4c93296e0439857b4569850b178a01385e82e9ad"},
|
||||||
|
{file = "asyncpg-0.30.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5df69d55add4efcd25ea2a3b02025b669a285b767bfbf06e356d68dbce4234ff"},
|
||||||
|
{file = "asyncpg-0.30.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3479a0d9a852c7c84e822c073622baca862d1217b10a02dd57ee4a7a081f708"},
|
||||||
|
{file = "asyncpg-0.30.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26683d3b9a62836fad771a18ecf4659a30f348a561279d6227dab96182f46144"},
|
||||||
|
{file = "asyncpg-0.30.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1b982daf2441a0ed314bd10817f1606f1c28b1136abd9e4f11335358c2c631cb"},
|
||||||
|
{file = "asyncpg-0.30.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1c06a3a50d014b303e5f6fc1e5f95eb28d2cee89cf58384b700da621e5d5e547"},
|
||||||
|
{file = "asyncpg-0.30.0-cp39-cp39-win32.whl", hash = "sha256:1b11a555a198b08f5c4baa8f8231c74a366d190755aa4f99aacec5970afe929a"},
|
||||||
|
{file = "asyncpg-0.30.0-cp39-cp39-win_amd64.whl", hash = "sha256:8b684a3c858a83cd876f05958823b68e8d14ec01bb0c0d14a6704c5bf9711773"},
|
||||||
|
{file = "asyncpg-0.30.0.tar.gz", hash = "sha256:c551e9928ab6707602f44811817f82ba3c446e018bfe1d3abecc8ba5f3eac851"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
async-timeout = {version = ">=4.0.3", markers = "python_version < \"3.11.0\""}
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
docs = ["Sphinx (>=8.1.3,<8.2.0)", "sphinx-rtd-theme (>=1.2.2)"]
|
||||||
|
gssauth = ["gssapi", "sspilib"]
|
||||||
|
test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0,<24.2.0)", "gssapi", "k5test", "mypy (>=1.8.0,<1.9.0)", "sspilib", "uvloop (>=0.15.3)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
|
@ -511,4 +590,4 @@ files = [
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "19f999486896e58ce5aad4e148e87fb8a81e4178b8dd86ad7d40049b4f892131"
|
content-hash = "bee1ff3c639641805049c37fc57b55a4ef93de7f9dd1585e6bf6c9530852df5f"
|
||||||
|
|
|
@ -12,6 +12,7 @@ pytest = "^8.3.4"
|
||||||
sqlalchemy = "^2.0.37"
|
sqlalchemy = "^2.0.37"
|
||||||
psycopg2 = "^2.9.10"
|
psycopg2 = "^2.9.10"
|
||||||
python-dotenv = "^1.0.1"
|
python-dotenv = "^1.0.1"
|
||||||
|
asyncpg = "^0.30.0"
|
||||||
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
|
|
Loading…
Reference in a new issue