Browse Source

Start using GINO

rewrite
noirscape 1 year ago
parent
commit
fcbf0146bf
12 changed files with 187 additions and 54 deletions
  1. +139
    -0
      .gitignore
  2. +0
    -1
      TODO
  3. +11
    -2
      client.py
  4. +20
    -29
      db.py
  5. +1
    -1
      db_models/__init__.py
  6. +4
    -7
      db_models/asset_store.py
  7. +0
    -2
      db_models/base.py
  8. +3
    -0
      db_models/gino.py
  9. +5
    -8
      db_models/moderation.py
  10. +1
    -1
      main.py
  11. +2
    -2
      models/management_guild.py
  12. +1
    -1
      requirements.txt

+ 139
- 0
.gitignore View File

@ -1,3 +1,142 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# App related content
secure.yml
config.yml


+ 0
- 1
TODO View File

@ -1 +0,0 @@
- Set up alembic

+ 11
- 2
client.py View File

@ -11,7 +11,7 @@ from models.management_guild import ManagementGuild
from db import DBOperationsManager
class KirigiriBot(commands.Bot):
def __init__(self, db_path: str, support_guild_invite: str, support_guild_id: int, management_guild: int, post_ready_callback=None, **kwargs):
def __init__(self, db_path: str, support_guild_invite: str, support_guild: int, management_guild: int, post_ready_callback=None, **kwargs):
"""
Initialize KirigiriBot. Accepts the same arguments as commands.Bot, in addition to a couple of extra ones.
@ -21,11 +21,12 @@ class KirigiriBot(commands.Bot):
"""
super().__init__(**kwargs)
self.support_guild_invite = support_guild_invite
self.support_guild_id = support_guild_id
self.support_guild = support_guild
self.management_guild_id = management_guild
self.db_manager = DBOperationsManager(db_path)
self.load_modules()
self._cache_ready = asyncio.Event()
self._connected_to_database = asyncio.Event()
self._post_ready_callback = post_ready_callback
def load_modules(self, skip_names=None):
@ -46,6 +47,9 @@ class KirigiriBot(commands.Bot):
async def wait_for_cache_to_ready(self):
await self._cache_ready.wait()
async def _connect_database(self):
await self.db_manager.connect_database()
async def on_ready(self):
"""
Initializes the bot. Sets up the required information for the bot to fully function.
@ -56,5 +60,10 @@ class KirigiriBot(commands.Bot):
# mark the cache as ready
self._cache_ready.set()
# connect the database
if self._connected_to_database.is_set():
await self._connect_database()
self._connected_to_database.set()
if self._post_ready_callback:
await self._post_ready_callback()

+ 20
- 29
db.py View File

@ -1,51 +1,37 @@
# stdlib
from typing import Union
# external libraries
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# internal files
import db_models
class DatabaseManager():
def __init__(self, db_path):
self.engine = create_engine(db_path)
db_models.Base.metadata.bind = self.engine
self.db_session = sessionmaker(bind=self.engine)
from db_models import db
class DBAssetStoreManager():
def __init__(self, db_manager):
self.db_manager = db_manager
def __init__(self):
pass
def get_asset_url(self, id) -> Union[None, str]:
async def get_asset_url(self, id) -> Union[None, str]:
"""
Get an asset's url by the ID.
Returns None if the ID is not found.
"""
session = self.db_manager.db_session()
result = session.query(db_models.AssetStore).filter(db_models.AssetStore.id == id).scalar()
if result: # if this isn't none (scalar returns none if no results)
result = result.url # ...we map the result's url to the result variable
return result
asset = await db_models.AssetStore.get(id)
if asset: # if this isn't none (scalar returns none if no results)
return asset.url
return None
def store_asset(self, id, url) -> str:
async def store_asset(self, id, url) -> str:
"""
Store or update an asset by ID.
Returns the URL of the asset.
"""
new_asset = db_models.AssetStore(id=id, url=url)
session = self.db_manager.db_session()
session.merge(new_asset)
session.commit()
await db_models.AssetStore.create(id=id, url=url)
return url
class DBModerationManager():
def __init__(self, db_manager):
self.db_manager = db_manager
self._mod_cache = [] # Internal mod cache. This is used to prevent unneccesary database calls.
def __init__(self):
self._mod_cache = {} # Internal mod cache. This is used to prevent unneccesary database calls.
def get_rank_from_cache(self, guild_id, user_id):
pass
@ -57,6 +43,11 @@ class DBModerationManager():
pass
class DBOperationsManager():
def __init__(self, db_path):
self.db_manager = DatabaseManager(db_path)
self.asset_store = DBAssetStoreManager(self.db_manager)
def __init__(self):
self.asset_store = DBAssetStoreManager()
async def connect_database(self, db_path):
await db.set_bind(db_path)
async def disconnect_database(self):
await db.pop_bind().close()

+ 1
- 1
db_models/__init__.py View File

@ -1,3 +1,3 @@
from .base import Base
from .gino import db
from .asset_store import AssetStore
from .moderation import Moderation, ModRankEnum

+ 4
- 7
db_models/asset_store.py View File

@ -1,11 +1,8 @@
# external libraries
from sqlalchemy import Column, Integer, Text
# internal files
from .base import Base
from .gino import db
class AssetStore(Base):
class AssetStore(db.Model):
__tablename__ = "asset_store"
id = Column(Integer, primary_key=True)
url = Column(Text)
id = db.Column(db.Integer(), primary_key=True)
url = db.Column(db.Unicode())

+ 0
- 2
db_models/base.py View File

@ -1,2 +0,0 @@
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

+ 3
- 0
db_models/gino.py View File

@ -0,0 +1,3 @@
from gino import Gino
db = Gino()

+ 5
- 8
db_models/moderation.py View File

@ -1,11 +1,8 @@
# stdlib
import enum
# external libraries
from sqlalchemy import Column, Integer, Text, Enum
# internal files
from .base import Base
from .gino import db
class ModRankEnum(enum.Enum):
no_rank = 0
@ -13,8 +10,8 @@ class ModRankEnum(enum.Enum):
op = 2
super_op = 3
class Moderation(Base):
class Moderation(db.Model):
__tablename__ = "moderation"
guild_id = Column(Integer, primary_key=True)
user_id = Column(Integer, primary_key=True)
mod_rank = Column(Enum(ModRankEnum), nullable=False)
guild_id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), primary_key=True)
mod_rank = db.Column(db.Enum(ModRankEnum), nullable=False)

+ 1
- 1
main.py View File

@ -25,7 +25,7 @@ def main():
args = parse_cli_args()
config, token = load_config()
if args["run"]:
bot = KirigiriBot(config.db_path, config.management_guild_id, command_prefix=config.prefix)
bot = KirigiriBot(config.db_path, support_guild_invite=config.support_guild_invite, support_guild=config.support_guild, management_guild=config.management_guild_id, command_prefix=config.prefix)
bot.run(token)
if __name__ == "__main__":

+ 2
- 2
models/management_guild.py View File

@ -35,11 +35,11 @@ class ManagementGuild:
Returns the new URL.
"""
result = self.bot.db_manager.asset_store.get_asset_url(id)
result = await self.bot.db_manager.asset_store.get_asset_url(id)
if not result:
filestream = io.BytesIO()
await asset.save(filestream)
message = await self.image_log.send(file=discord.File(filestream, filename))
url = message.attachments[0].url
result = self.bot.db_manager.asset_store.store_asset(id, url)
result = await self.bot.db_manager.asset_store.store_asset(id, url)
return result

+ 1
- 1
requirements.txt View File

@ -1,5 +1,5 @@
discord.py
pyyaml
docopt
sqlalchemy
logzero
gino

Loading…
Cancel
Save