mirror of
https://github.com/RYGhub/royalnet.git
synced 2024-11-27 13:34:28 +00:00
Continue
This commit is contained in:
parent
cb9ff43a6c
commit
839ae802e2
5 changed files with 119 additions and 78 deletions
|
@ -17,23 +17,17 @@ classifiers = [
|
||||||
# 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}
|
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
|
discord_py = {git = "https://github.com/Rapptz/discord.py", optional=true} # discord.py 1.2.4 is missing Go Live related methods
|
||||||
pynacl = {version="^1.3.0", optional=true} # This requires libffi-dev and python3.*-dev to be installed on Linux systems
|
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}
|
ffmpeg_python = {version="~0.2.0", optional=true}
|
||||||
youtube_dl = {version="*", optional=true}
|
youtube_dl = {version="*", optional=true}
|
||||||
|
|
||||||
sqlalchemy = {version="^1.3.10", 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 = {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
|
psycopg2_binary = {version="^2.8.4", optional=true} # Prebuilt alternative to psycopg2, not recommended
|
||||||
|
starlette = {version="^0.12.13", optional=true}
|
||||||
starlette = {version="0.12.13", optional=true}
|
sentry_sdk = {version="~0.13.2", optional=true}
|
||||||
|
|
||||||
# Optional dependencies
|
# Optional dependencies
|
||||||
[tool.poetry.extras]
|
[tool.poetry.extras]
|
||||||
|
@ -43,11 +37,11 @@ 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"]
|
||||||
|
|
|
@ -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}...")
|
||||||
|
self.running = True
|
||||||
|
try:
|
||||||
uvicorn.run(self.starlette, host=address, port=port)
|
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'}>"
|
||||||
|
|
|
@ -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}>"
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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]}"
|
||||||
|
|
Loading…
Reference in a new issue