1
Fork 0
mirror of https://github.com/RYGhub/royalnet.git synced 2024-11-23 19:44:20 +00:00
This commit is contained in:
Steffo 2019-11-12 16:00:43 +01:00
parent cb9ff43a6c
commit 839ae802e2
5 changed files with 119 additions and 78 deletions

View file

@ -1,54 +1,48 @@
[tool.poetry] [tool.poetry]
name = "royalnet" name = "royalnet"
version = "5.1a1" version = "5.1a1"
description = "A multipurpose bot and web framework" description = "A multipurpose bot and web framework"
authors = ["Stefano Pigozzi <ste.pigozzi@gmail.com>"] authors = ["Stefano Pigozzi <ste.pigozzi@gmail.com>"]
license = "AGPL-3.0+" license = "AGPL-3.0+"
readme = "README.md" readme = "README.md"
homepage = "https://github.com/Steffo99/royalnet" homepage = "https://github.com/Steffo99/royalnet"
documentation = "https://gh.steffo.eu/royalnet/" documentation = "https://gh.steffo.eu/royalnet/"
classifiers = [ classifiers = [
"Development Status :: 3 - Alpha", "Development Status :: 3 - Alpha",
"Operating System :: OS Independent", "Operating System :: OS Independent",
"Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.7",
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)" "License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)"
] ]
# Library dependencies # Library dependencies
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.8" python = "^3.8"
dateparser = "^0.7.2"
dateparser = "^0.7.2" python_telegram_bot = {version="^12.2.0", optional=true}
discord_py = {git = "https://github.com/Rapptz/discord.py", optional=true} # discord.py 1.2.4 is missing Go Live related methods
python_telegram_bot = {version="^12.2.0", optional=true} pynacl = {version="^1.3.0", optional=true} # This requires libffi-dev and python3.*-dev to be installed on Linux systems
ffmpeg_python = {version="~0.2.0", optional=true}
discord_py = {git = "https://github.com/Rapptz/discord.py", optional=true} # discord.py 1.2.4 is missing Go Live related methods youtube_dl = {version="*", optional=true}
pynacl = {version="^1.3.0", optional=true} # This requires libffi-dev and python3.*-dev to be installed on Linux systems sqlalchemy = {version="^1.3.10", optional=true}
psycopg2 = {version="^2.8.4", optional=true} # Requires quite a bit of stuff http://initd.org/psycopg/docs/install.html#install-from-source
ffmpeg_python = {version="~0.2.0", optional=true} psycopg2_binary = {version="^2.8.4", optional=true} # Prebuilt alternative to psycopg2, not recommended
youtube_dl = {version="*", optional=true} starlette = {version="^0.12.13", optional=true}
sentry_sdk = {version="~0.13.2", optional=true}
sqlalchemy = {version="^1.3.10", optional=true}
psycopg2 = {version="^2.8.4", optional=true} # Requires quite a bit of stuff http://initd.org/psycopg/docs/install.html#install-from-source
psycopg2_binary = {version="^2.8.4", optional=true} # Prebuilt alternative to psycopg2, not recommended
starlette = {version="0.12.13", optional=true}
# Optional dependencies # Optional dependencies
[tool.poetry.extras] [tool.poetry.extras]
telegram = ["python_telegram_bot"] telegram = ["python_telegram_bot"]
discord = ["discord_py", "pynacl"] discord = ["discord_py", "pynacl"]
alchemy_easy = ["sqlalchemy", "psycopg2_binary"] alchemy_easy = ["sqlalchemy", "psycopg2_binary"]
alchemy_hard = ["sqlalchemy", "psycopg2"] alchemy_hard = ["sqlalchemy", "psycopg2"]
bard = ["ffmpeg_python", "youtube_dl"] bard = ["ffmpeg_python", "youtube_dl"]
constellation = ["starlette"] constellation = ["starlette"]
sentry = ["sentry_sdk"]
# Development dependencies # Development dependencies
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^5.2.2" # There are none
[build-system] [build-system]
requires = ["poetry>=0.12"] requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api" build-backend = "poetry.masonry.api"

View file

@ -35,12 +35,26 @@ class Constellation:
exc_stars = [] exc_stars = []
self.secrets_name: str = secrets_name self.secrets_name: str = secrets_name
"""The secrets_name this Constellation is currently using."""
self.running: bool = False
"""Is the Constellation currently running?"""
log.info(f"Creating Starlette in {'Debug' if __debug__ else 'Production'} mode...") log.info(f"Creating Starlette in {'Debug' if __debug__ else 'Production'} mode...")
self.starlette = Starlette(debug=debug) self.starlette = Starlette(debug=debug)
"""The :class:`Starlette` app."""
log.info(f"Creating Alchemy with Tables: {' '.join([table.__name__ for table in tables])}") log.debug("Finding required Tables...")
tables = set()
for SelectedPageStar in page_stars:
tables = tables.union(SelectedPageStar.tables)
for SelectedExcStar in exc_stars:
tables = tables.union(SelectedExcStar.tables)
log.debug(f"Found Tables: {' '.join([table.__name__ for table in tables])}")
log.info(f"Creating Alchemy...")
self.alchemy: royalnet.database.Alchemy = royalnet.database.Alchemy(database_uri=database_uri, tables=tables) self.alchemy: royalnet.database.Alchemy = royalnet.database.Alchemy(database_uri=database_uri, tables=tables)
"""The :class:`Alchemy: of this Constellation."""
log.info("Registering PageStars...") log.info("Registering PageStars...")
for SelectedPageStar in page_stars: for SelectedPageStar in page_stars:
@ -82,17 +96,25 @@ class Constellation:
if sentry_dsn: if sentry_dsn:
# noinspection PyUnreachableCode # noinspection PyUnreachableCode
if __debug__: if __debug__:
release = "DEV" release = f"Dev"
else: else:
release = royalnet.version.semantic release = f"{royalnet.version.semantic}"
log.info(f"Sentry: enabled (Royalnet {release})") log.debug("Initializing Sentry...")
sentry_sdk.init(sentry_dsn, sentry_sdk.init(sentry_dsn,
integrations=[AioHttpIntegration(), integrations=[AioHttpIntegration(),
SqlalchemyIntegration(), SqlalchemyIntegration(),
LoggingIntegration(event_level=None)], LoggingIntegration(event_level=None)],
release=release) release=release)
log.info(f"Sentry: enabled (Royalnet {release})")
else: else:
log.info("Sentry: disabled") log.info("Sentry: disabled")
# Run the server # Run the server
log.info(f"Running constellation server on {address}:{port}...") log.info(f"Running Constellation on {address}:{port}...")
uvicorn.run(self.starlette, host=address, port=port) self.running = True
try:
uvicorn.run(self.starlette, host=address, port=port)
finally:
self.running = False
def __repr__(self):
return f"<{self.__class__.__qualname__}: {'running' if self.running else 'inactive'}>"

View file

@ -36,6 +36,9 @@ class Star:
"""A shortcut for the session :func:`asynccontextmanager` of the :class:`Constellation`.""" """A shortcut for the session :func:`asynccontextmanager` of the :class:`Constellation`."""
return self.constellation.alchemy.session_acm return self.constellation.alchemy.session_acm
def __repr__(self):
return f"<{self.__class__.__qualname__}>"
class PageStar(Star): class PageStar(Star):
"""A PageStar is a class representing a single route of the website (for example, ``/api/user/get``). """A PageStar is a class representing a single route of the website (for example, ``/api/user/get``).
@ -64,6 +67,9 @@ class PageStar(Star):
""" """
def __repr__(self):
return f"<{self.__class__.__qualname__}: {self.path}>"
class ExceptionStar(Star): class ExceptionStar(Star):
"""An ExceptionStar is a class that handles an :class:`Exception` raised by another star by returning a different """An ExceptionStar is a class that handles an :class:`Exception` raised by another star by returning a different
@ -79,3 +85,6 @@ class ExceptionStar(Star):
error: Union[Type[Exception], int] error: Union[Type[Exception], int]
"""The error that should be handled by this star. It should be either a subclass of :exc:`Exception`, """The error that should be handled by this star. It should be either a subclass of :exc:`Exception`,
or the :class:`int` of an HTTP error code.""" or the :class:`int` of an HTTP error code."""
def __repr__(self):
return f"<{self.__class__.__qualname__}: handles {self.error}>"

View file

@ -5,7 +5,7 @@ from .escaping import telegram_escape, discord_escape
from .safeformat import safeformat from .safeformat import safeformat
from .classdictjanitor import cdj from .classdictjanitor import cdj
from .sleepuntil import sleep_until from .sleepuntil import sleep_until
from .formatters import andformat, plusformat, fileformat, ytdldateformat, numberemojiformat, splitstring, ordinalformat from .formatters import andformat, plusformat, underscorize, ytdldateformat, numberemojiformat, splitstring, ordinalformat
from .urluuid import to_urluuid, from_urluuid from .urluuid import to_urluuid, from_urluuid
__all__ = [ __all__ = [
@ -16,7 +16,7 @@ __all__ = [
"plusformat", "plusformat",
"andformat", "andformat",
"plusformat", "plusformat",
"fileformat", "underscorize",
"ytdldateformat", "ytdldateformat",
"numberemojiformat", "numberemojiformat",
"telegram_escape", "telegram_escape",

View file

@ -2,16 +2,29 @@ import typing
import re import re
def andformat(l: typing.List[str], middle=", ", final=" and ") -> str: def andformat(l: typing.Collection[str], middle=", ", final=" and ") -> str:
"""Convert a :py:class:`list` to a :py:class:`str` by adding ``final`` between the last two elements and ``middle`` between the others. """Convert a iterable (such as a :class:`list`) to a :class:`str` by adding ``final`` between the last two elements and ``middle`` between the others.
Parameters: Args:
l: the input :py:class:`list`. l: the input iterable.
middle: the :py:class:`str` to be added between the middle elements. middle: the :class:`str` to be added between the middle elements.
final: the :py:class:`str` to be added between the last two elements. final: the :class:`str` to be added between the last two elements.
Returns: Returns:
The resulting :py:class:`str`.""" The resulting :py:class:`str`.
Examples:
::
>>> andformat(["Steffo", "Kappa", "Proto"])
"Steffo, Kappa and Proto"
>>> andformat(["Viktya", "Sensei", "Cate"], final=" e ")
"Viktya, Sensei e Cate"
>>> andformat(["Paltri", "Spaggia", "Gesù", "Mallllco"], middle="+", final="+")
"Paltri+Spaggia+Gesù+Mallllco"
"""
result = "" result = ""
for index, item in enumerate(l): for index, item in enumerate(l):
result += item result += item
@ -22,42 +35,45 @@ def andformat(l: typing.List[str], middle=", ", final=" and ") -> str:
return result return result
def plusformat(i: int, empty_if_zero: bool = False) -> str: def underscorize(string: str) -> str:
"""Convert an :py:class:`int` to a :py:class:`str`, prepending a ``+`` if it's greater than 0. """Replace all non-word characters in a :class:`str` with underscores.
Parameters: It is particularly useful when you want to use random strings from the Internet as filenames.
i: the :py:class:`int` to convert.
empty_if_zero: Return an empty string if ``i`` is zero.
Returns:
The resulting :py:class:`str`."""
if i == 0 and empty_if_zero:
return ""
if i > 0:
return f"+{i}"
return str(i)
def fileformat(string: str) -> str:
"""Ensure a string can be used as a filename by replacing all non-word characters with underscores.
Parameters: Parameters:
string: the input string. string: the input string.
Returns: Returns:
A valid filename string.""" The resulting string.
Example:
::
>>> underscorize("LE EPIC PRANK [GONE WRONG!?!?]")
"LE EPIC PRANK _GONE WRONG_____"
"""
return re.sub(r"\W", "_", string) return re.sub(r"\W", "_", string)
def ytdldateformat(string: typing.Optional[str], separator: str = "-") -> str: def ytdldateformat(string: typing.Optional[str], separator: str = "-") -> str:
"""Convert the weird date string returned by ``youtube-dl`` into the ``YYYY-MM-DD`` format. """Convert the date :class:`str` returned by :mod:`youtube-dl` into the ``YYYY-MM-DD`` format.
Parameters: Parameters:
string: the input string, in the ``YYYYMMDD`` format. string: the input string, in the ``YYYYMMDD`` format used by :mod:`youtube_dl`.
separator: the string to add between the years, the months and the days. Defaults to ``-``. separator: the string to add between the years, the months and the days. Defaults to ``-``.
Returns: Returns:
The resulting string, in the format ``YYYY-MM-DD`` format.""" The resulting string in the new format.
Example:
::
>>> ytdldateformat("20111111")
"2011-11-11"
>>> ytdldateformat("20200202", separator=".")
"2020.02.02"
"""
if string is None: if string is None:
return "" return ""
return f"{string[0:4]}{separator}{string[4:6]}{separator}{string[6:8]}" return f"{string[0:4]}{separator}{string[4:6]}{separator}{string[6:8]}"