Lots of abstraction, ref #121

This commit is contained in:
Zeva Rose 2022-02-09 14:18:56 -07:00
parent 0a9b8a3adc
commit 3d2dc03d70
24 changed files with 352 additions and 391 deletions

View file

@ -24,7 +24,7 @@ restart_ctx = None
jarvis = Snake(intents=intents, default_prefix="!", sync_interactions=jconfig.sync) jarvis = Snake(intents=intents, default_prefix="!", sync_interactions=jconfig.sync)
__version__ = "2.0.0a0" __version__ = "2.0.0a1"
@listen() @listen()

View file

@ -3,6 +3,7 @@ import re
from datetime import datetime, timedelta from datetime import datetime, timedelta
from dis_snek import InteractionContext, Permissions, Snake from dis_snek import InteractionContext, Permissions, Snake
from dis_snek.client.utils.misc_utils import find, find_all
from dis_snek.ext.paginators import Paginator from dis_snek.ext.paginators import Paginator
from dis_snek.models.discord.embed import EmbedField from dis_snek.models.discord.embed import EmbedField
from dis_snek.models.discord.user import User from dis_snek.models.discord.user import User
@ -13,9 +14,10 @@ from dis_snek.models.snek.application_commands import (
slash_option, slash_option,
) )
from dis_snek.models.snek.command import check from dis_snek.models.snek.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Ban, Unban
from jarvis.db.models import Ban, Unban from jarvis.utils import build_embed
from jarvis.utils import build_embed, find, find_all
from jarvis.utils.cachecog import CacheCog from jarvis.utils.cachecog import CacheCog
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -242,7 +244,9 @@ class BanCog(CacheCog):
# We take advantage of the previous checks to save CPU cycles # We take advantage of the previous checks to save CPU cycles
if not discord_ban_info: if not discord_ban_info:
if isinstance(user, int): if isinstance(user, int):
database_ban_info = Ban.objects(guild=ctx.guild.id, user=user, active=True).first() database_ban_info = await Ban.find_one(
q(guild=ctx.guild.id, user=user, active=True)
)
else: else:
search = { search = {
"guild": ctx.guild.id, "guild": ctx.guild.id,
@ -251,7 +255,7 @@ class BanCog(CacheCog):
} }
if discrim: if discrim:
search["discrim"] = discrim search["discrim"] = discrim
database_ban_info = Ban.objects(**search).first() database_ban_info = await Ban.find_one(q(**search))
if not discord_ban_info and not database_ban_info: if not discord_ban_info and not database_ban_info:
await ctx.send(f"Unable to find user {orig_user}", ephemeral=True) await ctx.send(f"Unable to find user {orig_user}", ephemeral=True)

View file

@ -7,8 +7,9 @@ from dis_snek.models.snek.application_commands import (
slash_option, slash_option,
) )
from dis_snek.models.snek.command import check from dis_snek.models.snek.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Autopurge, Purge
from jarvis.db.models import Autopurge, Purge
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -72,7 +73,7 @@ class PurgeCog(Scale):
await ctx.send("Delay must be < 5 minutes", ephemeral=True) await ctx.send("Delay must be < 5 minutes", ephemeral=True)
return return
autopurge = Autopurge.objects(guild=ctx.guild.id, channel=channel.id).first() autopurge = await Autopurge.find_one(q(guild=ctx.guild.id, channel=channel.id))
if autopurge: if autopurge:
await ctx.send("Autopurge already exists.", ephemeral=True) await ctx.send("Autopurge already exists.", ephemeral=True)
return return

View file

@ -1,5 +1,6 @@
"""J.A.R.V.I.S. RolepingCog.""" """J.A.R.V.I.S. RolepingCog."""
from dis_snek import InteractionContext, Permissions, Scale from dis_snek import InteractionContext, Permissions, Scale
from dis_snek.client.utils.misc_utils import find_all
from dis_snek.ext.paginators import Paginator from dis_snek.ext.paginators import Paginator
from dis_snek.models.discord.embed import EmbedField from dis_snek.models.discord.embed import EmbedField
from dis_snek.models.discord.role import Role from dis_snek.models.discord.role import Role
@ -10,9 +11,10 @@ from dis_snek.models.snek.application_commands import (
slash_option, slash_option,
) )
from dis_snek.models.snek.command import check from dis_snek.models.snek.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Roleping
from jarvis.db.models import Roleping from jarvis.utils import build_embed
from jarvis.utils import build_embed, find_all
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -25,7 +27,7 @@ class RolepingCog(Scale):
@slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_add(self, ctx: InteractionContext, role: Role) -> None: async def _roleping_add(self, ctx: InteractionContext, role: Role) -> None:
roleping = Roleping.objects(guild=ctx.guild.id, role=role.id).first() roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=role.id))
if roleping: if roleping:
await ctx.send(f"Role `{role.name}` already in roleping.", ephemeral=True) await ctx.send(f"Role `{role.name}` already in roleping.", ephemeral=True)
return return
@ -123,7 +125,7 @@ class RolepingCog(Scale):
async def _roleping_bypass_user( async def _roleping_bypass_user(
self, ctx: InteractionContext, user: Member, rping: Role self, ctx: InteractionContext, user: Member, rping: Role
) -> None: ) -> None:
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first() roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=rping.id))
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True)
return return
@ -164,7 +166,7 @@ class RolepingCog(Scale):
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _roleping_bypass_role(self, ctx: InteractionContext, role: Role, rping: Role) -> None: async def _roleping_bypass_role(self, ctx: InteractionContext, role: Role, rping: Role) -> None:
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first() roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=rping.id))
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True)
return return
@ -203,7 +205,7 @@ class RolepingCog(Scale):
async def _roleping_restore_user( async def _roleping_restore_user(
self, ctx: InteractionContext, user: Member, rping: Role self, ctx: InteractionContext, user: Member, rping: Role
) -> None: ) -> None:
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first() roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=rping.id))
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True)
return return
@ -232,7 +234,7 @@ class RolepingCog(Scale):
async def _roleping_restore_role( async def _roleping_restore_role(
self, ctx: InteractionContext, role: Role, rping: Role self, ctx: InteractionContext, role: Role, rping: Role
) -> None: ) -> None:
roleping = Roleping.objects(guild=ctx.guild.id, role=rping.id).first() roleping = await Roleping.find_one(q(guild=ctx.guild.id, role=rping.id))
if not roleping: if not roleping:
await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True) await ctx.send(f"Roleping not configured for {rping.mention}", ephemeral=True)
return return

View file

@ -3,6 +3,7 @@ import re
from typing import Optional, Tuple from typing import Optional, Tuple
from dis_snek import InteractionContext, Permissions, Scale, Snake from dis_snek import InteractionContext, Permissions, Scale, Snake
from dis_snek.client.utils.misc_utils import find
from dis_snek.models.discord.channel import GuildText from dis_snek.models.discord.channel import GuildText
from dis_snek.models.snek.application_commands import ( from dis_snek.models.snek.application_commands import (
OptionTypes, OptionTypes,
@ -10,10 +11,10 @@ from dis_snek.models.snek.application_commands import (
slash_option, slash_option,
) )
from dis_snek.models.snek.command import check from dis_snek.models.snek.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Autoreact
from jarvis.data.unicode import emoji_list from jarvis.data.unicode import emoji_list
from jarvis.db.models import Autoreact
from jarvis.utils import find
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -37,7 +38,7 @@ class AutoReactCog(Scale):
Returns: Returns:
Tuple of success? and error message Tuple of success? and error message
""" """
exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() exists = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id))
if exists: if exists:
return False, f"Autoreact already exists for {channel.mention}." return False, f"Autoreact already exists for {channel.mention}."
@ -93,10 +94,10 @@ class AutoReactCog(Scale):
if not find(lambda x: x.id == emoji_id, ctx.guild.emojis): if not find(lambda x: x.id == emoji_id, ctx.guild.emojis):
await ctx.send("Please use a custom emote from this server.", ephemeral=True) await ctx.send("Please use a custom emote from this server.", ephemeral=True)
return return
autoreact = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() autoreact = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id))
if not autoreact: if not autoreact:
self.create_autoreact(ctx, channel) self.create_autoreact(ctx, channel)
autoreact = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() autoreact = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id))
if emote in autoreact.reactions: if emote in autoreact.reactions:
await ctx.send( await ctx.send(
f"Emote already added to {channel.mention} autoreactions.", f"Emote already added to {channel.mention} autoreactions.",
@ -134,7 +135,7 @@ class AutoReactCog(Scale):
async def _autoreact_remove( async def _autoreact_remove(
self, ctx: InteractionContext, channel: GuildText, emote: str self, ctx: InteractionContext, channel: GuildText, emote: str
) -> None: ) -> None:
autoreact = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() autoreact = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id))
if not autoreact: if not autoreact:
await ctx.send( await ctx.send(
f"Please create autoreact first with /autoreact add {channel.mention} {emote}", f"Please create autoreact first with /autoreact add {channel.mention} {emote}",
@ -169,7 +170,7 @@ class AutoReactCog(Scale):
required=True, required=True,
) )
async def _autoreact_list(self, ctx: InteractionContext, channel: GuildText) -> None: async def _autoreact_list(self, ctx: InteractionContext, channel: GuildText) -> None:
exists = Autoreact.objects(guild=ctx.guild.id, channel=channel.id).first() exists = await Autoreact.find_one(q(guild=ctx.guild.id, channel=channel.id))
if not exists: if not exists:
await ctx.send( await ctx.send(
f"Please create autoreact first with /autoreact add {channel.mention} <emote>", f"Please create autoreact first with /autoreact add {channel.mention} <emote>",

View file

@ -10,8 +10,9 @@ from dis_snek.models.discord.user import Member, User
from dis_snek.models.snek.application_commands import slash_command from dis_snek.models.snek.application_commands import slash_command
from dis_snek.models.snek.command import cooldown from dis_snek.models.snek.command import cooldown
from dis_snek.models.snek.cooldowns import Buckets from dis_snek.models.snek.cooldowns import Buckets
from jarvis_core.db import q
from jarvis_core.db.models import Guess
from jarvis.db.models import Guess
from jarvis.utils import build_embed from jarvis.utils import build_embed
from jarvis.utils.cachecog import CacheCog from jarvis.utils.cachecog import CacheCog
@ -74,7 +75,7 @@ class CTCCog(CacheCog):
ephemeral=True, ephemeral=True,
) )
return return
guessed = Guess.objects(guess=guess).first() guessed = await Guess.find_one(q(guess=guess))
if guessed: if guessed:
await ctx.send("Already guessed, dipshit.", ephemeral=True) await ctx.send("Already guessed, dipshit.", ephemeral=True)
return return

View file

@ -4,12 +4,12 @@ import hashlib
import re import re
import subprocess # noqa: S404 import subprocess # noqa: S404
import uuid as uuidpy import uuid as uuidpy
from typing import Any, Union
import ulid as ulidpy import ulid as ulidpy
from bson import ObjectId from bson import ObjectId
from dis_snek import InteractionContext, Scale, Snake from dis_snek import InteractionContext, Scale, Snake
from dis_snek.models.discord.embed import EmbedField from dis_snek.models.discord.embed import EmbedField
from dis_snek.models.discord.message import Attachment
from dis_snek.models.snek.application_commands import ( from dis_snek.models.snek.application_commands import (
OptionTypes, OptionTypes,
SlashCommandChoice, SlashCommandChoice,
@ -18,8 +18,11 @@ from dis_snek.models.snek.application_commands import (
) )
from dis_snek.models.snek.command import cooldown from dis_snek.models.snek.command import cooldown
from dis_snek.models.snek.cooldowns import Buckets from dis_snek.models.snek.cooldowns import Buckets
from jarvis_core.filters import invites, url
from jarvis_core.util import convert_bytesize, hash
from jarvis_core.util.http import get_size
from jarvis.utils import build_embed, convert_bytesize from jarvis.utils import build_embed
supported_hashes = {x for x in hashlib.algorithms_guaranteed if "shake" not in x} supported_hashes = {x for x in hashlib.algorithms_guaranteed if "shake" not in x}
@ -36,29 +39,9 @@ UUID_VERIFY = re.compile(
re.IGNORECASE, re.IGNORECASE,
) )
invites = re.compile(
r"(?:https?://)?(?:www.)?(?:discord.(?:gg|io|me|li)|discord(?:app)?.com/invite)/([^\s/]+?)(?=\b)", # noqa: E501
flags=re.IGNORECASE,
)
UUID_GET = {3: uuidpy.uuid3, 5: uuidpy.uuid5} UUID_GET = {3: uuidpy.uuid3, 5: uuidpy.uuid5}
MAX_FILESIZE = 5 * (1024**3) # 5GB
def hash_obj(hash: Any, data: Union[str, bytes], text: bool = True) -> str:
"""Hash data with hash object.
Data can be text or binary
"""
if text:
hash.update(data.encode("UTF-8"))
return hash.hexdigest()
BSIZE = 65536
block_idx = 0
while block_idx * BSIZE < len(data):
block = data[BSIZE * block_idx : BSIZE * (block_idx + 1)]
hash.update(block)
block_idx += 1
return hash.hexdigest()
class DevCog(Scale): class DevCog(Scale):
@ -76,26 +59,47 @@ class DevCog(Scale):
name="data", name="data",
description="Data to hash", description="Data to hash",
opt_type=OptionTypes.STRING, opt_type=OptionTypes.STRING,
required=True, required=False,
)
@slash_option(
name="attach", description="File to hash", opt_type=OptionTypes.ATTACHMENT, required=False
) )
@cooldown(bucket=Buckets.USER, rate=1, interval=2) @cooldown(bucket=Buckets.USER, rate=1, interval=2)
async def _hash(self, ctx: InteractionContext, method: str, data: str) -> None: async def _hash(
if not data: self, ctx: InteractionContext, method: str, data: str = None, attach: Attachment = None
) -> None:
if not data and not attach:
await ctx.send( await ctx.send(
"No data to hash", "No data to hash",
ephemeral=True, ephemeral=True,
) )
return return
text = True if data and invites.match(data):
# Default to sha256, just in case await ctx.send("No hashing invites", ephemeral=True)
hash = getattr(hashlib, method, hashlib.sha256)() return
hex = hash_obj(hash, data, text) title = data
data_size = convert_bytesize(len(data)) if attach:
title = data if text else ctx.message.attachments[0].filename data = attach.url
title = attach.filename
elif url.match(data):
if await get_size(data) > MAX_FILESIZE:
await ctx.send("Please hash files that are <= 5GB in size", ephemeral=True)
return
title = data.split("/")[-1]
await ctx.defer()
try:
hexstr, size, c_type = await hash(data, method)
except Exception as e:
await ctx.send(f"Failed to hash data: ```\n{e}\n```", ephemeral=True)
return
data_size = convert_bytesize(size)
description = "Hashed using " + method description = "Hashed using " + method
fields = [ fields = [
EmbedField("Content Type", c_type, False),
EmbedField("Data Size", data_size, False), EmbedField("Data Size", data_size, False),
EmbedField("Hash", f"`{hex}`", False), EmbedField("Hash", f"`{hexstr}`", False),
] ]
embed = build_embed(title=title, description=description, fields=fields) embed = build_embed(title=title, description=description, fields=fields)

View file

@ -14,8 +14,9 @@ from dis_snek.models.snek.application_commands import (
) )
from dis_snek.models.snek.command import cooldown from dis_snek.models.snek.command import cooldown
from dis_snek.models.snek.cooldowns import Buckets from dis_snek.models.snek.cooldowns import Buckets
from jarvis_core.db import q
from jarvis_core.db.models import Joke
from jarvis.db.models import Joke
from jarvis.utils import build_embed from jarvis.utils import build_embed
@ -46,7 +47,7 @@ class JokeCog(Scale):
threshold = 500 # Minimum score threshold = 500 # Minimum score
result = None result = None
if id: if id:
result = Joke.objects(rid=id).first() result = await Joke.find_one(q(rid=id))
else: else:
pipeline = [ pipeline = [
{"$match": {"score": {"$gt": threshold}}}, {"$match": {"score": {"$gt": threshold}}},

View file

@ -4,8 +4,7 @@ from dis_snek.models.discord.user import User
from dis_snek.models.snek.checks import is_owner from dis_snek.models.snek.checks import is_owner
from dis_snek.models.snek.command import check from dis_snek.models.snek.command import check
from jarvis.config import reload_config from jarvis import jconfig
from jarvis.db.models import Config
class OwnerCog(Scale): class OwnerCog(Scale):
@ -17,7 +16,7 @@ class OwnerCog(Scale):
def __init__(self, bot: Snake): def __init__(self, bot: Snake):
self.bot = bot self.bot = bot
self.admins = Config.objects(key="admins").first() # self.admins = await Config.find_one(q(key="admins"))
@message_command(name="addadmin") @message_command(name="addadmin")
@check(is_owner()) @check(is_owner())
@ -27,7 +26,7 @@ class OwnerCog(Scale):
return return
self.admins.value.append(user.id) self.admins.value.append(user.id)
self.admins.save() self.admins.save()
reload_config() jconfig.reload()
await ctx.send(f"{user.mention} is now an admin. Use this power carefully.") await ctx.send(f"{user.mention} is now an admin. Use this power carefully.")
@message_command(name="deladmin") @message_command(name="deladmin")
@ -38,7 +37,7 @@ class OwnerCog(Scale):
return return
self.admins.value.remove(user.id) self.admins.value.remove(user.id)
self.admins.save() self.admins.save()
reload_config() jconfig.reload()
await ctx.send(f"{user.mention} is no longer an admin.") await ctx.send(f"{user.mention} is no longer an admin.")

View file

@ -2,6 +2,7 @@
import asyncio import asyncio
from dis_snek import InteractionContext, Permissions, Scale, Snake from dis_snek import InteractionContext, Permissions, Scale, Snake
from dis_snek.client.utils.misc_utils import get
from dis_snek.models.discord.components import ActionRow, Select, SelectOption from dis_snek.models.discord.components import ActionRow, Select, SelectOption
from dis_snek.models.discord.embed import EmbedField from dis_snek.models.discord.embed import EmbedField
from dis_snek.models.discord.role import Role from dis_snek.models.discord.role import Role
@ -12,9 +13,10 @@ from dis_snek.models.snek.application_commands import (
) )
from dis_snek.models.snek.command import check, cooldown from dis_snek.models.snek.command import check, cooldown
from dis_snek.models.snek.cooldowns import Buckets from dis_snek.models.snek.cooldowns import Buckets
from jarvis_core.db import q
from jarvis_core.db.models import Rolegiver
from jarvis.db.models import Rolegiver from jarvis.utils import build_embed
from jarvis.utils import build_embed, get
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -30,7 +32,7 @@ class RolegiverCog(Scale):
@slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True) @slash_option(name="role", description="Role to add", opt_type=OptionTypes.ROLE, required=True)
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _rolegiver_add(self, ctx: InteractionContext, role: Role) -> None: async def _rolegiver_add(self, ctx: InteractionContext, role: Role) -> None:
setting = Rolegiver.objects(guild=ctx.guild.id).first() setting = await Rolegiver.find_one(q(guild=ctx.guild.id))
if setting and role.id in setting.roles: if setting and role.id in setting.roles:
await ctx.send("Role already in rolegiver", ephemeral=True) await ctx.send("Role already in rolegiver", ephemeral=True)
return return
@ -80,7 +82,7 @@ class RolegiverCog(Scale):
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _rolegiver_remove(self, ctx: InteractionContext) -> None: async def _rolegiver_remove(self, ctx: InteractionContext) -> None:
setting = Rolegiver.objects(guild=ctx.guild.id).first() setting = await Rolegiver.find_one(q(guild=ctx.guild.id))
if not setting or (setting and not setting.roles): if not setting or (setting and not setting.roles):
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
return return
@ -162,7 +164,7 @@ class RolegiverCog(Scale):
@slash_command(name="rolegiver", sub_cmd_name="list", description="List rolegiver roles") @slash_command(name="rolegiver", sub_cmd_name="list", description="List rolegiver roles")
async def _rolegiver_list(self, ctx: InteractionContext) -> None: async def _rolegiver_list(self, ctx: InteractionContext) -> None:
setting = Rolegiver.objects(guild=ctx.guild.id).first() setting = await Rolegiver.find_one(q(guild=ctx.guild.id))
if not setting or (setting and not setting.roles): if not setting or (setting and not setting.roles):
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
return return
@ -198,7 +200,7 @@ class RolegiverCog(Scale):
@slash_command(name="role", sub_cmd_name="get", sub_cmd_description="Get a role") @slash_command(name="role", sub_cmd_name="get", sub_cmd_description="Get a role")
@cooldown(bucket=Buckets.USER, rate=1, interval=10) @cooldown(bucket=Buckets.USER, rate=1, interval=10)
async def _role_get(self, ctx: InteractionContext) -> None: async def _role_get(self, ctx: InteractionContext) -> None:
setting = Rolegiver.objects(guild=ctx.guild.id).first() setting = await Rolegiver.find_one(q(guild=ctx.guild.id))
if not setting or (setting and not setting.roles): if not setting or (setting and not setting.roles):
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
return return
@ -276,7 +278,7 @@ class RolegiverCog(Scale):
async def _role_remove(self, ctx: InteractionContext) -> None: async def _role_remove(self, ctx: InteractionContext) -> None:
user_roles = ctx.author.roles user_roles = ctx.author.roles
setting = Rolegiver.objects(guild=ctx.guild.id).first() setting = await Rolegiver.find_one(q(guild=ctx.guild.id))
if not setting or (setting and not setting.roles): if not setting or (setting and not setting.roles):
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
return return
@ -355,7 +357,7 @@ class RolegiverCog(Scale):
) )
@check(admin_or_permissions(Permissions.MANAGE_GUILD)) @check(admin_or_permissions(Permissions.MANAGE_GUILD))
async def _rolegiver_cleanup(self, ctx: InteractionContext) -> None: async def _rolegiver_cleanup(self, ctx: InteractionContext) -> None:
setting = Rolegiver.objects(guild=ctx.guild.id).first() setting = await Rolegiver.find_one(q(guild=ctx.guild.id))
if not setting or not setting.roles: if not setting or not setting.roles:
await ctx.send("Rolegiver has no roles", ephemeral=True) await ctx.send("Rolegiver has no roles", ephemeral=True)
guild_role_ids = [r.id for r in ctx.guild.roles] guild_role_ids = [r.id for r in ctx.guild.roles]

View file

@ -7,6 +7,7 @@ from discord.ext import commands
from discord.utils import find from discord.utils import find
from discord_slash import SlashContext, cog_ext from discord_slash import SlashContext, cog_ext
from discord_slash.utils.manage_commands import create_option from discord_slash.utils.manage_commands import create_option
from jarvis_core.db import q
from jarvis.db.models import Setting from jarvis.db.models import Setting
from jarvis.utils import build_embed from jarvis.utils import build_embed
@ -20,9 +21,9 @@ class SettingsCog(commands.Cog):
def __init__(self, bot: commands.Bot): def __init__(self, bot: commands.Bot):
self.bot = bot self.bot = bot
def update_settings(self, setting: str, value: Any, guild: int) -> bool: async def update_settings(self, setting: str, value: Any, guild: int) -> bool:
"""Update a guild setting.""" """Update a guild setting."""
existing = Setting.objects(setting=setting, guild=guild).first() existing = await Setting.find_one(q(setting=setting, guild=guild))
if not existing: if not existing:
existing = Setting(setting=setting, guild=guild, value=value) existing = Setting(setting=setting, guild=guild, value=value)
existing.value = value existing.value = value
@ -30,9 +31,12 @@ class SettingsCog(commands.Cog):
return updated is not None return updated is not None
def delete_settings(self, setting: str, guild: int) -> bool: async def delete_settings(self, setting: str, guild: int) -> bool:
"""Delete a guild setting.""" """Delete a guild setting."""
return Setting.objects(setting=setting, guild=guild).delete() existing = await Setting.find_one(q(setting=setting, guild=guild))
if existing:
return await existing.delete()
return False
@cog_ext.cog_subcommand( @cog_ext.cog_subcommand(
base="settings", base="settings",

View file

@ -1,5 +1,6 @@
"""J.A.R.V.I.S. Starboard Cog.""" """J.A.R.V.I.S. Starboard Cog."""
from dis_snek import InteractionContext, Permissions, Scale, Snake from dis_snek import InteractionContext, Permissions, Scale, Snake
from dis_snek.client.utils.misc_utils import find
from dis_snek.models.discord.channel import GuildText from dis_snek.models.discord.channel import GuildText
from dis_snek.models.discord.components import ActionRow, Select, SelectOption from dis_snek.models.discord.components import ActionRow, Select, SelectOption
from dis_snek.models.discord.message import Message from dis_snek.models.discord.message import Message
@ -11,9 +12,10 @@ from dis_snek.models.snek.application_commands import (
slash_option, slash_option,
) )
from dis_snek.models.snek.command import check from dis_snek.models.snek.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Star, Starboard
from jarvis.db.models import Star, Starboard from jarvis.utils import build_embed
from jarvis.utils import build_embed, find
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
supported_images = [ supported_images = [
@ -64,7 +66,7 @@ class StarboardCog(Scale):
await ctx.send("Channel must be a GuildText", ephemeral=True) await ctx.send("Channel must be a GuildText", ephemeral=True)
return return
exists = Starboard.objects(channel=channel.id, guild=ctx.guild.id).first() exists = await Starboard.find_one(q(channel=channel.id, guild=ctx.guild.id))
if exists: if exists:
await ctx.send(f"Starboard already exists at {channel.mention}.", ephemeral=True) await ctx.send(f"Starboard already exists at {channel.mention}.", ephemeral=True)
return return
@ -248,7 +250,7 @@ class StarboardCog(Scale):
if not isinstance(starboard, GuildText): if not isinstance(starboard, GuildText):
await ctx.send("Channel must be a GuildText channel", ephemeral=True) await ctx.send("Channel must be a GuildText channel", ephemeral=True)
return return
exists = Starboard.objects(channel=starboard.id, guild=ctx.guild.id).first() exists = await Starboard.find_one(q(channel=starboard.id, guild=ctx.guild.id))
if not exists: if not exists:
await ctx.send( await ctx.send(
f"Starboard does not exist in {starboard.mention}. Please create it first", f"Starboard does not exist in {starboard.mention}. Please create it first",

View file

@ -13,9 +13,10 @@ from dis_snek.models.snek.application_commands import (
slash_option, slash_option,
) )
from dis_snek.models.snek.command import check from dis_snek.models.snek.command import check
from jarvis_core.db import q
from jarvis_core.db.models import Twitter
from jarvis.config import get_config from jarvis import jconfig
from jarvis.db.models import Twitter
from jarvis.utils.permissions import admin_or_permissions from jarvis.utils.permissions import admin_or_permissions
@ -24,7 +25,7 @@ class TwitterCog(Scale):
def __init__(self, bot: Snake): def __init__(self, bot: Snake):
self.bot = bot self.bot = bot
config = get_config() config = jconfig
auth = tweepy.AppAuthHandler( auth = tweepy.AppAuthHandler(
config.twitter["consumer_key"], config.twitter["consumer_secret"] config.twitter["consumer_key"], config.twitter["consumer_secret"]
) )
@ -75,12 +76,12 @@ class TwitterCog(Scale):
) )
return return
count = Twitter.objects(guild=ctx.guild.id).count() count = len([i async for i in Twitter.find(guild=ctx.guild.id)])
if count >= 12: if count >= 12:
await ctx.send("Cannot follow more than 12 Twitter accounts", ephemeral=True) await ctx.send("Cannot follow more than 12 Twitter accounts", ephemeral=True)
return return
exists = Twitter.objects(twitter_id=account.id, guild=ctx.guild.id) exists = Twitter.find_one(q(twitter_id=account.id, guild=ctx.guild.id))
if exists: if exists:
await ctx.send("Twitter account already being followed in this guild", ephemeral=True) await ctx.send("Twitter account already being followed in this guild", ephemeral=True)
return return
@ -95,7 +96,7 @@ class TwitterCog(Scale):
retweets=retweets, retweets=retweets,
) )
t.save() await t.commit()
await ctx.send(f"Now following `@{handle}` in {channel.mention}") await ctx.send(f"Now following `@{handle}` in {channel.mention}")
@ -194,7 +195,7 @@ class TwitterCog(Scale):
handlemap = {str(x.id): x.handle for x in twitters} handlemap = {str(x.id): x.handle for x in twitters}
for to_update in context.context.values: for to_update in context.context.values:
t = Twitter.objects(guild=ctx.guild.id, id=ObjectId(to_update)).first() t = await Twitter.find_one(q(guild=ctx.guild.id, id=ObjectId(to_update)))()
t.retweets = retweets t.retweets = retweets
t.save() t.save()

View file

@ -7,8 +7,8 @@ from dis_snek.models.application_commands import slash_command
from dis_snek.models.discord.components import Button, ButtonStyles, spread_to_rows from dis_snek.models.discord.components import Button, ButtonStyles, spread_to_rows
from dis_snek.models.snek.command import cooldown from dis_snek.models.snek.command import cooldown
from dis_snek.models.snek.cooldowns import Buckets from dis_snek.models.snek.cooldowns import Buckets
from jarvis_core.db import q
from jarvis.db.models import Setting from jarvis_core.db.models import Setting
def create_layout() -> list: def create_layout() -> list:
@ -39,7 +39,7 @@ class VerifyCog(Scale):
@cooldown(bucket=Buckets.USER, rate=1, interval=15) @cooldown(bucket=Buckets.USER, rate=1, interval=15)
async def _verify(self, ctx: InteractionContext) -> None: async def _verify(self, ctx: InteractionContext) -> None:
await ctx.defer() await ctx.defer()
role = Setting.objects(guild=ctx.guild.id, setting="verified").first() role = await Setting.find_one(q(guild=ctx.guild.id, setting="verified"))
if not role: if not role:
await ctx.send("This guild has not enabled verification", delete_after=5) await ctx.send("This guild has not enabled verification", delete_after=5)
return return
@ -62,10 +62,10 @@ class VerifyCog(Scale):
for row in components: for row in components:
for component in row.components: for component in row.components:
component.disabled = True component.disabled = True
setting = Setting.objects(guild=ctx.guild.id, setting="verified").first() setting = await Setting.find_one(guild=ctx.guild.id, setting="verified")
role = await ctx.guild.get_role(setting.value) role = await ctx.guild.get_role(setting.value)
await ctx.author.add_roles(role, reason="Verification passed") await ctx.author.add_roles(role, reason="Verification passed")
setting = Setting.objects(guild=ctx.guild.id, setting="unverified").first() setting = await Setting.find_one(guild=ctx.guild.id, setting="unverified")
if setting: if setting:
role = await ctx.guild.get_role(setting.value) role = await ctx.guild.get_role(setting.value)
await ctx.author.remove_roles(role, reason="Verification passed") await ctx.author.remove_roles(role, reason="Verification passed")

View file

@ -1,8 +1,8 @@
"""J.A.R.V.I.S. Member event handler.""" """J.A.R.V.I.S. Member event handler."""
from dis_snek import Snake, listen from dis_snek import Snake, listen
from dis_snek.models.discord.user import Member from dis_snek.models.discord.user import Member
from jarvis_core.db import q
from jarvis.db.models import Setting from jarvis_core.db.models import Setting
class MemberEventHandler(object): class MemberEventHandler(object):
@ -16,7 +16,7 @@ class MemberEventHandler(object):
async def on_member_join(self, user: Member) -> None: async def on_member_join(self, user: Member) -> None:
"""Handle on_member_join event.""" """Handle on_member_join event."""
guild = user.guild guild = user.guild
unverified = Setting.objects(guild=guild.id, setting="unverified").first() unverified = await Setting.find_one(q(guild=guild.id, setting="unverified"))
if unverified: if unverified:
role = guild.get_role(unverified.value) role = guild.get_role(unverified.value)
if role not in user.roles: if role not in user.roles:

View file

@ -2,13 +2,15 @@
import re import re
from dis_snek import Snake, listen from dis_snek import Snake, listen
from dis_snek.client.utils.misc_utils import find, find_all
from dis_snek.models.discord.channel import DMChannel from dis_snek.models.discord.channel import DMChannel
from dis_snek.models.discord.embed import EmbedField from dis_snek.models.discord.embed import EmbedField
from dis_snek.models.discord.message import Message from dis_snek.models.discord.message import Message
from jarvis_core.db import q
from jarvis_core.db.models import Autopurge, Autoreact, Roleping, Setting, Warning
from jarvis.config import get_config import jarvis
from jarvis.db.models import Autopurge, Autoreact, Roleping, Setting, Warning from jarvis.utils import build_embed
from jarvis.utils import build_embed, find, find_all
invites = re.compile( invites = re.compile(
r"(?:https?://)?(?:www.)?(?:discord.(?:gg|io|me|li)|discord(?:app)?.com/invite)/([^\s/]+?)(?=\b)", # noqa: E501 r"(?:https?://)?(?:www.)?(?:discord.(?:gg|io|me|li)|discord(?:app)?.com/invite)/([^\s/]+?)(?=\b)", # noqa: E501
@ -26,16 +28,18 @@ class MessageEventHandler(object):
async def autopurge(self, message: Message) -> None: async def autopurge(self, message: Message) -> None:
"""Handle autopurge events.""" """Handle autopurge events."""
autopurge = Autopurge.objects(guild=message.guild.id, channel=message.channel.id).first() autopurge = await Autopurge.find_one(q(guild=message.guild.id, channel=message.channel.id))
if autopurge: if autopurge:
await message.delete(delay=autopurge.delay) await message.delete(delay=autopurge.delay)
async def autoreact(self, message: Message) -> None: async def autoreact(self, message: Message) -> None:
"""Handle autoreact events.""" """Handle autoreact events."""
autoreact = Autoreact.objects( autoreact = await Autoreact.find_one(
q(
guild=message.guild.id, guild=message.guild.id,
channel=message.channel.id, channel=message.channel.id,
).first() )
)
if autoreact: if autoreact:
for reaction in autoreact.reactions: for reaction in autoreact.reactions:
await message.add_reaction(reaction) await message.add_reaction(reaction)
@ -50,10 +54,10 @@ class MessageEventHandler(object):
) )
content = re.sub(r"\s+", "", message.content) content = re.sub(r"\s+", "", message.content)
match = invites.search(content) match = invites.search(content)
setting = Setting.objects(guild=message.guild.id, setting="noinvite").first() setting = await Setting.find_one(q(guild=message.guild.id, setting="noinvite"))
if not setting: if not setting:
setting = Setting(guild=message.guild.id, setting="noinvite", value=True) setting = Setting(guild=message.guild.id, setting="noinvite", value=True)
setting.save() await setting.commit()
if match: if match:
guild_invites = await message.guild.invites() guild_invites = await message.guild.invites()
allowed = [x.code for x in guild_invites] + [ allowed = [x.code for x in guild_invites] + [
@ -63,14 +67,15 @@ class MessageEventHandler(object):
] ]
if match.group(1) not in allowed and setting.value: if match.group(1) not in allowed and setting.value:
await message.delete() await message.delete()
_ = Warning( w = Warning(
active=True, active=True,
admin=get_config().client_id, admin=jarvis.jconfig.client_id,
duration=24, duration=24,
guild=message.guild.id, guild=message.guild.id,
reason="Sent an invite link", reason="Sent an invite link",
user=message.author.id, user=message.author.id,
).save() )
await w.commit()
fields = [ fields = [
EmbedField( EmbedField(
name="Reason", name="Reason",
@ -94,10 +99,12 @@ class MessageEventHandler(object):
async def massmention(self, message: Message) -> None: async def massmention(self, message: Message) -> None:
"""Handle massmention events.""" """Handle massmention events."""
massmention = Setting.objects( massmention = await Setting.find_one(
q(
guild=message.guild.id, guild=message.guild.id,
setting="massmention", setting="massmention",
).first() )
)
if ( if (
massmention massmention
and massmention.value > 0 # noqa: W503 and massmention.value > 0 # noqa: W503
@ -105,14 +112,15 @@ class MessageEventHandler(object):
- (1 if message.author in message.mentions else 0) # noqa: W503 - (1 if message.author in message.mentions else 0) # noqa: W503
> massmention.value # noqa: W503 > massmention.value # noqa: W503
): ):
_ = Warning( w = Warning(
active=True, active=True,
admin=get_config().client_id, admin=jarvis.jconfig.client_id,
duration=24, duration=24,
guild=message.guild.id, guild=message.guild.id,
reason="Mass Mention", reason="Mass Mention",
user=message.author.id, user=message.author.id,
).save() )
await w.commit()
fields = [EmbedField(name="Reason", value="Mass Mention", inline=False)] fields = [EmbedField(name="Reason", value="Mass Mention", inline=False)]
embed = build_embed( embed = build_embed(
title="Warning", title="Warning",
@ -130,7 +138,7 @@ class MessageEventHandler(object):
async def roleping(self, message: Message) -> None: async def roleping(self, message: Message) -> None:
"""Handle roleping events.""" """Handle roleping events."""
rolepings = Roleping.objects(guild=message.guild.id, active=True) rolepings = await Roleping.find(q(guild=message.guild.id, active=True))
if not rolepings: if not rolepings:
return return
@ -169,14 +177,15 @@ class MessageEventHandler(object):
break break
if role_in_rolepings and user_missing_role and not user_is_admin and not user_has_bypass: if role_in_rolepings and user_missing_role and not user_is_admin and not user_has_bypass:
_ = Warning( w = Warning(
active=True, active=True,
admin=get_config().client_id, admin=jarvis.jconfig.client_id,
duration=24, duration=24,
guild=message.guild.id, guild=message.guild.id,
reason="Pinged a blocked role/user with a blocked role", reason="Pinged a blocked role/user with a blocked role",
user=message.author.id, user=message.author.id,
).save() )
await w.commit()
fields = [ fields = [
EmbedField( EmbedField(
name="Reason", name="Reason",

View file

@ -1,23 +1,24 @@
"""J.A.R.V.I.S. reminder background task handler.""" """J.A.R.V.I.S. reminder background task handler."""
from asyncio import to_thread
from datetime import datetime, timedelta from datetime import datetime, timedelta
from dis_snek.ext.tasks.task import Task from dis_snek.ext.tasks.task import Task
from dis_snek.ext.tasks.triggers import IntervalTrigger from dis_snek.ext.tasks.triggers import IntervalTrigger
from jarvis_core.db import q
from jarvis_core.db.models import Reminder
import jarvis import jarvis
from jarvis.db.models import Reminder
from jarvis.utils import build_embed from jarvis.utils import build_embed
async def _remind() -> None: @Task.create(trigger=IntervalTrigger(seconds=15))
"""J.A.R.V.I.S. reminder blocking task.""" async def remind() -> None:
reminders = Reminder.objects(remind_at__lte=datetime.utcnow() + timedelta(seconds=30)) """J.A.R.V.I.S. reminder background task."""
for reminder in reminders: reminders = Reminder.find(q(remind_at__lte=datetime.utcnow() + timedelta(seconds=30)))
async for reminder in reminders:
if reminder.remind_at <= datetime.utcnow(): if reminder.remind_at <= datetime.utcnow():
user = await jarvis.jarvis.fetch_user(reminder.user) user = await jarvis.jarvis.fetch_user(reminder.user)
if not user: if not user:
reminder.delete() await reminder.delete()
continue continue
embed = build_embed( embed = build_embed(
title="You have a reminder", title="You have a reminder",
@ -41,10 +42,4 @@ async def _remind() -> None:
"but I couldn't send it to you." "but I couldn't send it to you."
) )
finally: finally:
reminder.delete() await reminder.delete()
@Task.create(trigger=IntervalTrigger(seconds=15))
async def remind() -> None:
"""J.A.R.V.I.S. reminder background task."""
await to_thread(_remind)

View file

@ -1,41 +1,40 @@
"""J.A.R.V.I.S. twitter background task handler.""" """J.A.R.V.I.S. twitter background task handler."""
import logging import logging
from asyncio import to_thread
from datetime import datetime, timedelta from datetime import datetime, timedelta
import tweepy import tweepy
from dis_snek.ext.tasks.task import Task from dis_snek.ext.tasks.task import Task
from dis_snek.ext.tasks.triggers import IntervalTrigger from dis_snek.ext.tasks.triggers import IntervalTrigger
from jarvis_core.db import q
from jarvis_core.db.models import Twitter
import jarvis import jarvis
from jarvis.config import get_config
from jarvis.db.models import Twitter
logger = logging.getLogger("jarvis") logger = logging.getLogger("jarvis")
@Task.create(trigger=IntervalTrigger(minutes=1))
async def tweets() -> None:
"""J.A.R.V.I.S. twitter background task."""
config = jarvis.config.get_config()
__auth = tweepy.AppAuthHandler( __auth = tweepy.AppAuthHandler(
get_config().twitter["consumer_key"], get_config().twitter["consumer_secret"] config.twitter["consumer_key"], jarvis.jconfig.twitter["consumer_secret"]
) )
__api = tweepy.API(__auth) __api = tweepy.API(__auth)
async def _tweets() -> None:
"""J.A.R.V.I.S. twitter blocking task."""
guild_cache = {} guild_cache = {}
channel_cache = {} channel_cache = {}
twitters = Twitter.objects(active=True) twitters = Twitter.find(q(active=True))
for twitter in twitters: async for twitter in twitters:
try: try:
if not twitter.twitter_id or not twitter.last_sync: if not twitter.twitter_id or not twitter.last_sync:
user = __api.get_user(screen_name=twitter.handle) user = __api.get_user(screen_name=twitter.handle)
twitter.twitter_id = user.id twitter.update(
twitter.handle = user.screen_name q(twitter_id=user.id, handle=user.screen_name, last_sync=datetime.now())
twitter.last_sync = datetime.now() )
if twitter.last_sync + timedelta(hours=1) <= datetime.now(): if twitter.last_sync + timedelta(hours=1) <= datetime.now():
user = __api.get_user(id=twitter.twitter_id) user = __api.get_user(id=twitter.twitter_id)
twitter.handle = user.screen_name twitter.update(q(handle=user.screen_name, last_sync=datetime.now()))
twitter.last_sync = datetime.now()
if tweets := __api.user_timeline(id=twitter.twitter_id): if tweets := __api.user_timeline(id=twitter.twitter_id):
guild_id = twitter.guild guild_id = twitter.guild
@ -58,13 +57,7 @@ async def _tweets() -> None:
f"`@{twitter.handle}` {verb}tweeted this at <t:{timestamp}:f>: {url}" f"`@{twitter.handle}` {verb}tweeted this at <t:{timestamp}:f>: {url}"
) )
newest = max(tweets, key=lambda x: x.id) newest = max(tweets, key=lambda x: x.id)
twitter.last_tweet = newest.id twitter.update(q(last_tweet=newest.id))
twitter.save() await twitter.commit()
except Exception as e: except Exception as e:
logger.error(f"Error with tweets: {e}") logger.error(f"Error with tweets: {e}")
@Task.create(trigger=IntervalTrigger(minutes=1))
async def tweets() -> None:
"""J.A.R.V.I.S. twitter background task."""
await to_thread(_tweets)

View file

@ -1,33 +1,28 @@
"""J.A.R.V.I.S. unban background task handler.""" """J.A.R.V.I.S. unban background task handler."""
from asyncio import to_thread
from datetime import datetime, timedelta from datetime import datetime, timedelta
from dis_snek.ext.tasks.task import Task from dis_snek.ext.tasks.task import Task
from dis_snek.ext.tasks.triggers import IntervalTrigger from dis_snek.ext.tasks.triggers import IntervalTrigger
from jarvis_core.db import q
from jarvis_core.db.models import Ban, Unban
import jarvis import jarvis
from jarvis.config import get_config
from jarvis.db.models import Ban, Unban
jarvis_id = get_config().client_id
@Task.create(IntervalTrigger(minutes=10))
async def _unban() -> None: async def _unban() -> None:
"""J.A.R.V.I.S. unban blocking task.""" """J.A.R.V.I.S. unban background task."""
bans = Ban.objects(type="temp", active=True) jarvis_id = jarvis.jconfig.client_id
unbans = [] bans = Ban.find(q(type="temp", active=True))
for ban in bans: async for ban in bans:
if ban.created_at + timedelta(hours=ban.duration) < datetime.utcnow() + timedelta( if ban.created_at + timedelta(hours=ban.duration) < datetime.now() + timedelta(minutes=10):
minutes=10
):
guild = await jarvis.jarvis.get_guild(ban.guild) guild = await jarvis.jarvis.get_guild(ban.guild)
user = await jarvis.jarvis.get_user(ban.user) user = await jarvis.jarvis.get_user(ban.user)
if user: if user:
await guild.unban(user=user, reason="Ban expired") await guild.unban(user=user, reason="Ban expired")
ban.active = False ban.update(q(active=False))
ban.save() await ban.commit()
unbans.append( u = Unban(
Unban(
user=user.id, user=user.id,
guild=guild.id, guild=guild.id,
username=user.name, username=user.name,
@ -35,12 +30,4 @@ async def _unban() -> None:
admin=jarvis_id, admin=jarvis_id,
reason="Ban expired", reason="Ban expired",
) )
) await u.commit()
if unbans:
Unban.objects().insert(unbans)
@Task.create(IntervalTrigger(minutes=10))
async def unban() -> None:
"""J.A.R.V.I.S. unban background task."""
await to_thread(_unban)

View file

@ -1,23 +1,17 @@
"""J.A.R.V.I.S. unwarn background task handler.""" """J.A.R.V.I.S. unwarn background task handler."""
from asyncio import to_thread
from datetime import datetime, timedelta from datetime import datetime, timedelta
from dis_snek.ext.tasks.task import Task from dis_snek.ext.tasks.task import Task
from dis_snek.ext.tasks.triggers import IntervalTrigger from dis_snek.ext.tasks.triggers import IntervalTrigger
from jarvis_core.db import q
from jarvis.db.models import Warning from jarvis_core.db.models import Warning
async def _unwarn() -> None:
"""J.A.R.V.I.S. unwarn blocking task."""
warns = Warning.objects(active=True)
for warn in warns:
if warn.created_at + timedelta(hours=warn.duration) < datetime.utcnow():
warn.active = False
warn.save()
@Task.create(IntervalTrigger(hours=1)) @Task.create(IntervalTrigger(hours=1))
async def unwarn() -> None: async def unwarn() -> None:
"""J.A.R.V.I.S. unwarn background task.""" """J.A.R.V.I.S. unwarn background task."""
await to_thread(_unwarn) warns = Warning.find(q(active=True))
async for warn in warns:
if warn.created_at + timedelta(hours=warn.duration) < datetime.now():
warn.update(q(active=False))
await warn.commit()

View file

@ -1,7 +1,6 @@
"""J.A.R.V.I.S. Utility Functions.""" """J.A.R.V.I.S. Utility Functions."""
from datetime import datetime from datetime import datetime
from pkgutil import iter_modules from pkgutil import iter_modules
from typing import Any, Callable, Iterable, List, Optional, TypeVar
import git import git
from dis_snek.models.discord.embed import Embed from dis_snek.models.discord.embed import Embed
@ -10,9 +9,7 @@ import jarvis.cogs
import jarvis.db import jarvis.db
from jarvis.config import get_config from jarvis.config import get_config
__all__ = ["field", "db", "cachecog", "permissions"] __all__ = ["cachecog", "permissions"]
T = TypeVar("T")
def build_embed( def build_embed(
@ -38,27 +35,6 @@ def build_embed(
return embed return embed
def convert_bytesize(b: int) -> str:
"""Convert bytes amount to human readable."""
b = float(b)
sizes = ["B", "KB", "MB", "GB", "TB", "PB"]
size = 0
while b >= 1024 and size < len(sizes) - 1:
b = b / 1024
size += 1
return "{:0.3f} {}".format(b, sizes[size])
def unconvert_bytesize(size: int, ending: str) -> int:
"""Convert human readable to bytes."""
ending = ending.upper()
sizes = ["B", "KB", "MB", "GB", "TB", "PB"]
if ending == "B":
return size
# Rounding is only because bytes cannot be partial
return round(size * (1024 ** sizes.index(ending)))
def get_extensions(path: str = jarvis.cogs.__path__) -> list: def get_extensions(path: str = jarvis.cogs.__path__) -> list:
"""Get J.A.R.V.I.S. cogs.""" """Get J.A.R.V.I.S. cogs."""
config = get_config() config = get_config()
@ -85,99 +61,3 @@ def get_repo_hash() -> str:
"""J.A.R.V.I.S. current branch hash.""" """J.A.R.V.I.S. current branch hash."""
repo = git.Repo(".") repo = git.Repo(".")
return repo.head.object.hexsha return repo.head.object.hexsha
def find(predicate: Callable, sequence: Iterable) -> Optional[Any]:
"""
Find the first element in a sequence that matches the predicate.
??? Hint "Example Usage:"
```python
member = find(lambda m: m.name == "UserName", guild.members)
```
Args:
predicate: A callable that returns a boolean value
sequence: A sequence to be searched
Returns:
A match if found, otherwise None
"""
for el in sequence:
if predicate(el):
return el
return None
def find_all(predicate: Callable, sequence: Iterable) -> List[Any]:
"""
Find all elements in a sequence that match the predicate.
??? Hint "Example Usage:"
```python
members = find_all(lambda m: m.name == "UserName", guild.members)
```
Args:
predicate: A callable that returns a boolean value
sequence: A sequence to be searched
Returns:
A list of matches
"""
return [el for el in sequence if predicate(el)]
def get(sequence: Iterable, **kwargs: Any) -> Optional[Any]:
"""
Find the first element in a sequence that matches all attrs.
??? Hint "Example Usage:"
```python
channel = get(guild.channels, nsfw=False, category="General")
```
Args:
sequence: A sequence to be searched
kwargs: Keyword arguments to search the sequence for
Returns:
A match if found, otherwise None
"""
if not kwargs:
return sequence[0]
for el in sequence:
if any(not hasattr(el, attr) for attr in kwargs.keys()):
continue
if all(getattr(el, attr) == value for attr, value in kwargs.items()):
return el
return None
def get_all(sequence: Iterable, **kwargs: Any) -> List[Any]:
"""
Find all elements in a sequence that match all attrs.
??? Hint "Example Usage:"
```python
channels = get_all(guild.channels, nsfw=False, category="General")
```
Args:
sequence: A sequence to be searched
kwargs: Keyword arguments to search the sequence for
Returns:
A list of matches
"""
if not kwargs:
return sequence
matches = []
for el in sequence:
if any(not hasattr(el, attr) for attr in kwargs.keys()):
continue
if all(getattr(el, attr) == value for attr, value in kwargs.items()):
matches.append(el)
return matches

View file

@ -2,11 +2,10 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from dis_snek import InteractionContext, Scale, Snake from dis_snek import InteractionContext, Scale, Snake
from dis_snek.client.utils.misc_utils import find
from dis_snek.ext.tasks.task import Task from dis_snek.ext.tasks.task import Task
from dis_snek.ext.tasks.triggers import IntervalTrigger from dis_snek.ext.tasks.triggers import IntervalTrigger
from jarvis.utils import find
class CacheCog(Scale): class CacheCog(Scale):
"""Cog wrapper for command caching.""" """Cog wrapper for command caching."""

212
poetry.lock generated
View file

@ -136,7 +136,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]] [[package]]
name = "dis-snek" name = "dis-snek"
version = "5.0.0" version = "6.0.0"
description = "An API wrapper for Discord filled with snakes" description = "An API wrapper for Discord filled with snakes"
category = "main" category = "main"
optional = false optional = false
@ -212,6 +212,28 @@ requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"] colors = ["colorama (>=0.4.3,<0.5.0)"]
plugins = ["setuptools"] plugins = ["setuptools"]
[[package]]
name = "jarvis-core"
version = "0.2.1"
description = ""
category = "main"
optional = false
python-versions = "^3.10"
develop = false
[package.dependencies]
dis-snek = "*"
motor = "^2.5.1"
orjson = "^3.6.6"
PyYAML = "^6.0"
umongo = "^3.1.0"
[package.source]
type = "git"
url = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git"
reference = "main"
resolved_reference = "0e627eae725abb1e6f3766c5dc94bd80d0ac6702"
[[package]] [[package]]
name = "jedi" name = "jedi"
version = "0.18.1" version = "0.18.1"
@ -235,6 +257,20 @@ category = "dev"
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
[[package]]
name = "marshmallow"
version = "3.14.1"
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
category = "main"
optional = false
python-versions = ">=3.6"
[package.extras]
dev = ["pytest", "pytz", "simplejson", "mypy (==0.910)", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "pre-commit (>=2.4,<3.0)", "tox"]
docs = ["sphinx (==4.3.0)", "sphinx-issues (==1.2.0)", "alabaster (==0.7.12)", "sphinx-version-warning (==1.1.2)", "autodocsumm (==0.2.7)"]
lint = ["mypy (==0.910)", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "pre-commit (>=2.4,<3.0)"]
tests = ["pytest", "pytz", "simplejson"]
[[package]] [[package]]
name = "mccabe" name = "mccabe"
version = "0.6.1" version = "0.6.1"
@ -254,6 +290,20 @@ python-versions = ">=3.6"
[package.dependencies] [package.dependencies]
pymongo = ">=3.4,<4.0" pymongo = ">=3.4,<4.0"
[[package]]
name = "motor"
version = "2.5.1"
description = "Non-blocking MongoDB driver for Tornado or asyncio"
category = "main"
optional = false
python-versions = ">=3.5.2"
[package.dependencies]
pymongo = ">=3.12,<4"
[package.extras]
encryption = ["pymongo[encryption] (>=3.12,<4)"]
[[package]] [[package]]
name = "multidict" name = "multidict"
version = "6.0.2" version = "6.0.2"
@ -272,7 +322,7 @@ python-versions = "*"
[[package]] [[package]]
name = "numpy" name = "numpy"
version = "1.22.1" version = "1.22.2"
description = "NumPy is the fundamental package for array computing with Python." description = "NumPy is the fundamental package for array computing with Python."
category = "main" category = "main"
optional = false optional = false
@ -337,7 +387,7 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
[[package]] [[package]]
name = "pillow" name = "pillow"
version = "9.0.0" version = "9.0.1"
description = "Python Imaging Library (Fork)" description = "Python Imaging Library (Fork)"
category = "main" category = "main"
optional = false optional = false
@ -345,7 +395,7 @@ python-versions = ">=3.7"
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "2.4.1" version = "2.5.0"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev" category = "dev"
optional = false optional = false
@ -597,7 +647,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
[[package]] [[package]]
name = "tomli" name = "tomli"
version = "2.0.0" version = "2.0.1"
description = "A lil' TOML parser" description = "A lil' TOML parser"
category = "main" category = "main"
optional = false optional = false
@ -637,6 +687,23 @@ category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
[[package]]
name = "umongo"
version = "3.1.0"
description = "sync/async MongoDB ODM, yes."
category = "main"
optional = false
python-versions = ">=3.7"
[package.dependencies]
marshmallow = ">=3.10.0"
pymongo = ">=3.7.0"
[package.extras]
mongomock = ["mongomock"]
motor = ["motor (>=2.0,<3.0)"]
txmongo = ["txmongo (>=19.2.0)"]
[[package]] [[package]]
name = "urllib3" name = "urllib3"
version = "1.26.8" version = "1.26.8"
@ -681,7 +748,7 @@ multidict = ">=4.0"
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "8a1e6e29ff70363abddad36082a494c4ce1f9cc672fe7aff30b6d5b596d50dac" content-hash = "d34963008bb31a5168210290f44909aa684a363455b2d59fe792f41918ec4705"
[metadata.files] [metadata.files]
aiohttp = [ aiohttp = [
@ -820,8 +887,8 @@ colorama = [
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
] ]
dis-snek = [ dis-snek = [
{file = "dis-snek-5.0.0.tar.gz", hash = "sha256:cc733b510d6b20523a8067f19b6d9b99804c13e37d78cd6e0fc401098adbca27"}, {file = "dis-snek-6.0.0.tar.gz", hash = "sha256:3abe2af832bd87adced01ebc697e418b25871a4158ac8ba2e202d8fbb2921f44"},
{file = "dis_snek-5.0.0-py3-none-any.whl", hash = "sha256:d1d50ba468ad6b0788e9281eb9d83f6eb2f8d964c1212ccd0e3fb33295462263"}, {file = "dis_snek-6.0.0-py3-none-any.whl", hash = "sha256:106cb08b0cc982c59db31be01ee529e4d7273835de7f418562d8e6b24d7f965d"},
] ]
flake8 = [ flake8 = [
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"}, {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
@ -904,6 +971,7 @@ isort = [
{file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
{file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
] ]
jarvis-core = []
jedi = [ jedi = [
{file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"}, {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"},
{file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"}, {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"},
@ -947,6 +1015,10 @@ lazy-object-proxy = [
{file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"}, {file = "lazy_object_proxy-1.7.1-cp39-cp39-win_amd64.whl", hash = "sha256:677ea950bef409b47e51e733283544ac3d660b709cfce7b187f5ace137960d61"},
{file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"}, {file = "lazy_object_proxy-1.7.1-pp37.pp38-none-any.whl", hash = "sha256:d66906d5785da8e0be7360912e99c9188b70f52c422f9fc18223347235691a84"},
] ]
marshmallow = [
{file = "marshmallow-3.14.1-py3-none-any.whl", hash = "sha256:04438610bc6dadbdddb22a4a55bcc7f6f8099e69580b2e67f5a681933a1f4400"},
{file = "marshmallow-3.14.1.tar.gz", hash = "sha256:4c05c1684e0e97fe779c62b91878f173b937fe097b356cd82f793464f5bc6138"},
]
mccabe = [ mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"}, {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"}, {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
@ -955,6 +1027,10 @@ mongoengine = [
{file = "mongoengine-0.23.1-py3-none-any.whl", hash = "sha256:3d1c8b9f5d43144bd726a3f01e58d2831c6fb112960a4a60b3a26fa85e026ab3"}, {file = "mongoengine-0.23.1-py3-none-any.whl", hash = "sha256:3d1c8b9f5d43144bd726a3f01e58d2831c6fb112960a4a60b3a26fa85e026ab3"},
{file = "mongoengine-0.23.1.tar.gz", hash = "sha256:de275e70cd58891dc46eef43369c522ce450dccb6d6f1979cbc9b93e6bdaf6cb"}, {file = "mongoengine-0.23.1.tar.gz", hash = "sha256:de275e70cd58891dc46eef43369c522ce450dccb6d6f1979cbc9b93e6bdaf6cb"},
] ]
motor = [
{file = "motor-2.5.1-py3-none-any.whl", hash = "sha256:961fdceacaae2c7236c939166f66415be81be8bbb762da528386738de3a0f509"},
{file = "motor-2.5.1.tar.gz", hash = "sha256:663473f4498f955d35db7b6f25651cb165514c247136f368b84419cb7635f6b8"},
]
multidict = [ multidict = [
{file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"}, {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"},
{file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"}, {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac0e27844758d7177989ce406acc6a83c16ed4524ebc363c1f748cba184d89d3"},
@ -1021,28 +1097,25 @@ mypy-extensions = [
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
] ]
numpy = [ numpy = [
{file = "numpy-1.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d62d6b0870b53799204515145935608cdeb4cebb95a26800b6750e48884cc5b"}, {file = "numpy-1.22.2-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:515a8b6edbb904594685da6e176ac9fbea8f73a5ebae947281de6613e27f1956"},
{file = "numpy-1.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:831f2df87bd3afdfc77829bc94bd997a7c212663889d56518359c827d7113b1f"}, {file = "numpy-1.22.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:76a4f9bce0278becc2da7da3b8ef854bed41a991f4226911a24a9711baad672c"},
{file = "numpy-1.22.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8d1563060e77096367952fb44fca595f2b2f477156de389ce7c0ade3aef29e21"}, {file = "numpy-1.22.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:168259b1b184aa83a514f307352c25c56af111c269ffc109d9704e81f72e764b"},
{file = "numpy-1.22.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69958735d5e01f7b38226a6c6e7187d72b7e4d42b6b496aca5860b611ca0c193"}, {file = "numpy-1.22.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3556c5550de40027d3121ebbb170f61bbe19eb639c7ad0c7b482cd9b560cd23b"},
{file = "numpy-1.22.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45a7dfbf9ed8d68fd39763940591db7637cf8817c5bce1a44f7b56c97cbe211e"}, {file = "numpy-1.22.2-cp310-cp310-win_amd64.whl", hash = "sha256:aafa46b5a39a27aca566198d3312fb3bde95ce9677085efd02c86f7ef6be4ec7"},
{file = "numpy-1.22.1-cp310-cp310-win_amd64.whl", hash = "sha256:7e957ca8112c689b728037cea9c9567c27cf912741fabda9efc2c7d33d29dfa1"}, {file = "numpy-1.22.2-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:55535c7c2f61e2b2fc817c5cbe1af7cb907c7f011e46ae0a52caa4be1f19afe2"},
{file = "numpy-1.22.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:800dfeaffb2219d49377da1371d710d7952c9533b57f3d51b15e61c4269a1b5b"}, {file = "numpy-1.22.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:60cb8e5933193a3cc2912ee29ca331e9c15b2da034f76159b7abc520b3d1233a"},
{file = "numpy-1.22.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:65f5e257987601fdfc63f1d02fca4d1c44a2b85b802f03bd6abc2b0b14648dd2"}, {file = "numpy-1.22.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b536b6840e84c1c6a410f3a5aa727821e6108f3454d81a5cd5900999ef04f89"},
{file = "numpy-1.22.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:632e062569b0fe05654b15ef0e91a53c0a95d08ffe698b66f6ba0f927ad267c2"}, {file = "numpy-1.22.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2638389562bda1635b564490d76713695ff497242a83d9b684d27bb4a6cc9d7a"},
{file = "numpy-1.22.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d245a2bf79188d3f361137608c3cd12ed79076badd743dc660750a9f3074f7c"}, {file = "numpy-1.22.2-cp38-cp38-win32.whl", hash = "sha256:6767ad399e9327bfdbaa40871be4254d1995f4a3ca3806127f10cec778bd9896"},
{file = "numpy-1.22.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26b4018a19d2ad9606ce9089f3d52206a41b23de5dfe8dc947d2ec49ce45d015"}, {file = "numpy-1.22.2-cp38-cp38-win_amd64.whl", hash = "sha256:03ae5850619abb34a879d5f2d4bb4dcd025d6d8fb72f5e461dae84edccfe129f"},
{file = "numpy-1.22.1-cp38-cp38-win32.whl", hash = "sha256:f8ad59e6e341f38266f1549c7c2ec70ea0e3d1effb62a44e5c3dba41c55f0187"}, {file = "numpy-1.22.2-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:d76a26c5118c4d96e264acc9e3242d72e1a2b92e739807b3b69d8d47684b6677"},
{file = "numpy-1.22.1-cp38-cp38-win_amd64.whl", hash = "sha256:60f19c61b589d44fbbab8ff126640ae712e163299c2dd422bfe4edc7ec51aa9b"}, {file = "numpy-1.22.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:15efb7b93806d438e3bc590ca8ef2f953b0ce4f86f337ef4559d31ec6cf9d7dd"},
{file = "numpy-1.22.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2db01d9838a497ba2aa9a87515aeaf458f42351d72d4e7f3b8ddbd1eba9479f2"}, {file = "numpy-1.22.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:badca914580eb46385e7f7e4e426fea6de0a37b9e06bec252e481ae7ec287082"},
{file = "numpy-1.22.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bcd19dab43b852b03868796f533b5f5561e6c0e3048415e675bec8d2e9d286c1"}, {file = "numpy-1.22.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94dd11d9f13ea1be17bac39c1942f527cbf7065f94953cf62dfe805653da2f8f"},
{file = "numpy-1.22.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:78bfbdf809fc236490e7e65715bbd98377b122f329457fffde206299e163e7f3"}, {file = "numpy-1.22.2-cp39-cp39-win32.whl", hash = "sha256:8cf33634b60c9cef346663a222d9841d3bbbc0a2f00221d6bcfd0d993d5543f6"},
{file = "numpy-1.22.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c51124df17f012c3b757380782ae46eee85213a3215e51477e559739f57d9bf6"}, {file = "numpy-1.22.2-cp39-cp39-win_amd64.whl", hash = "sha256:59153979d60f5bfe9e4c00e401e24dfe0469ef8da6d68247439d3278f30a180f"},
{file = "numpy-1.22.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88d54b7b516f0ca38a69590557814de2dd638d7d4ed04864826acaac5ebb8f01"}, {file = "numpy-1.22.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a176959b6e7e00b5a0d6f549a479f869829bfd8150282c590deee6d099bbb6e"},
{file = "numpy-1.22.1-cp39-cp39-win32.whl", hash = "sha256:b5ec9a5eaf391761c61fd873363ef3560a3614e9b4ead17347e4deda4358bca4"}, {file = "numpy-1.22.2.zip", hash = "sha256:076aee5a3763d41da6bef9565fdf3cb987606f567cd8b104aded2b38b7b47abf"},
{file = "numpy-1.22.1-cp39-cp39-win_amd64.whl", hash = "sha256:4ac4d7c9f8ea2a79d721ebfcce81705fc3cd61a10b731354f1049eb8c99521e8"},
{file = "numpy-1.22.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e60ef82c358ded965fdd3132b5738eade055f48067ac8a5a8ac75acc00cad31f"},
{file = "numpy-1.22.1.zip", hash = "sha256:e348ccf5bc5235fc405ab19d53bec215bb373300e5523c7b476cc0da8a5e9973"},
] ]
oauthlib = [ oauthlib = [
{file = "oauthlib-3.2.0-py3-none-any.whl", hash = "sha256:6db33440354787f9b7f3a6dbd4febf5d0f93758354060e802f6c06cb493022fe"}, {file = "oauthlib-3.2.0-py3-none-any.whl", hash = "sha256:6db33440354787f9b7f3a6dbd4febf5d0f93758354060e802f6c06cb493022fe"},
@ -1092,42 +1165,45 @@ pathspec = [
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
] ]
pillow = [ pillow = [
{file = "Pillow-9.0.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:113723312215b25c22df1fdf0e2da7a3b9c357a7d24a93ebbe80bfda4f37a8d4"}, {file = "Pillow-9.0.1-1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a5d24e1d674dd9d72c66ad3ea9131322819ff86250b30dc5821cbafcfa0b96b4"},
{file = "Pillow-9.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bb47a548cea95b86494a26c89d153fd31122ed65255db5dcbc421a2d28eb3379"}, {file = "Pillow-9.0.1-1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2632d0f846b7c7600edf53c48f8f9f1e13e62f66a6dbc15191029d950bfed976"},
{file = "Pillow-9.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31b265496e603985fad54d52d11970383e317d11e18e856971bdbb86af7242a4"}, {file = "Pillow-9.0.1-1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9618823bd237c0d2575283f2939655f54d51b4527ec3972907a927acbcc5bfc"},
{file = "Pillow-9.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d154ed971a4cc04b93a6d5b47f37948d1f621f25de3e8fa0c26b2d44f24e3e8f"}, {file = "Pillow-9.0.1-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:9bfdb82cdfeccec50aad441afc332faf8606dfa5e8efd18a6692b5d6e79f00fd"},
{file = "Pillow-9.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fe92813d208ce8aa7d76da878bdc84b90809f79ccbad2a288e9bcbeac1d9bd"}, {file = "Pillow-9.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5100b45a4638e3c00e4d2320d3193bdabb2d75e79793af7c3eb139e4f569f16f"},
{file = "Pillow-9.0.0-cp310-cp310-win32.whl", hash = "sha256:d5dcea1387331c905405b09cdbfb34611050cc52c865d71f2362f354faee1e9f"}, {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:528a2a692c65dd5cafc130de286030af251d2ee0483a5bf50c9348aefe834e8a"},
{file = "Pillow-9.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:52abae4c96b5da630a8b4247de5428f593465291e5b239f3f843a911a3cf0105"}, {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f29d831e2151e0b7b39981756d201f7108d3d215896212ffe2e992d06bfe049"},
{file = "Pillow-9.0.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:72c3110228944019e5f27232296c5923398496b28be42535e3b2dc7297b6e8b6"}, {file = "Pillow-9.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:855c583f268edde09474b081e3ddcd5cf3b20c12f26e0d434e1386cc5d318e7a"},
{file = "Pillow-9.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97b6d21771da41497b81652d44191489296555b761684f82b7b544c49989110f"}, {file = "Pillow-9.0.1-cp310-cp310-win32.whl", hash = "sha256:d9d7942b624b04b895cb95af03a23407f17646815495ce4547f0e60e0b06f58e"},
{file = "Pillow-9.0.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72f649d93d4cc4d8cf79c91ebc25137c358718ad75f99e99e043325ea7d56100"}, {file = "Pillow-9.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:81c4b81611e3a3cb30e59b0cf05b888c675f97e3adb2c8672c3154047980726b"},
{file = "Pillow-9.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aaf07085c756f6cb1c692ee0d5a86c531703b6e8c9cae581b31b562c16b98ce"}, {file = "Pillow-9.0.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:413ce0bbf9fc6278b2d63309dfeefe452835e1c78398efb431bab0672fe9274e"},
{file = "Pillow-9.0.0-cp37-cp37m-win32.whl", hash = "sha256:03b27b197deb4ee400ed57d8d4e572d2d8d80f825b6634daf6e2c18c3c6ccfa6"}, {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80fe64a6deb6fcfdf7b8386f2cf216d329be6f2781f7d90304351811fb591360"},
{file = "Pillow-9.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a09a9d4ec2b7887f7a088bbaacfd5c07160e746e3d47ec5e8050ae3b2a229e9f"}, {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cef9c85ccbe9bee00909758936ea841ef12035296c748aaceee535969e27d31b"},
{file = "Pillow-9.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:490e52e99224858f154975db61c060686df8a6b3f0212a678e5d2e2ce24675c9"}, {file = "Pillow-9.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d19397351f73a88904ad1aee421e800fe4bbcd1aeee6435fb62d0a05ccd1030"},
{file = "Pillow-9.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:500d397ddf4bbf2ca42e198399ac13e7841956c72645513e8ddf243b31ad2128"}, {file = "Pillow-9.0.1-cp37-cp37m-win32.whl", hash = "sha256:d21237d0cd37acded35154e29aec853e945950321dd2ffd1a7d86fe686814669"},
{file = "Pillow-9.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ebd8b9137630a7bbbff8c4b31e774ff05bbb90f7911d93ea2c9371e41039b52"}, {file = "Pillow-9.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:ede5af4a2702444a832a800b8eb7f0a7a1c0eed55b644642e049c98d589e5092"},
{file = "Pillow-9.0.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd0e5062f11cb3e730450a7d9f323f4051b532781026395c4323b8ad055523c4"}, {file = "Pillow-9.0.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b5b3f092fe345c03bca1e0b687dfbb39364b21ebb8ba90e3fa707374b7915204"},
{file = "Pillow-9.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f3b4522148586d35e78313db4db0df4b759ddd7649ef70002b6c3767d0fdeb7"}, {file = "Pillow-9.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:335ace1a22325395c4ea88e00ba3dc89ca029bd66bd5a3c382d53e44f0ccd77e"},
{file = "Pillow-9.0.0-cp38-cp38-win32.whl", hash = "sha256:0b281fcadbb688607ea6ece7649c5d59d4bbd574e90db6cd030e9e85bde9fecc"}, {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db6d9fac65bd08cea7f3540b899977c6dee9edad959fa4eaf305940d9cbd861c"},
{file = "Pillow-9.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5050d681bcf5c9f2570b93bee5d3ec8ae4cf23158812f91ed57f7126df91762"}, {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f154d173286a5d1863637a7dcd8c3437bb557520b01bddb0be0258dcb72696b5"},
{file = "Pillow-9.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:c2067b3bb0781f14059b112c9da5a91c80a600a97915b4f48b37f197895dd925"}, {file = "Pillow-9.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d4b1341ac07ae07eb2cc682f459bec932a380c3b122f5540432d8977e64eae"},
{file = "Pillow-9.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2d16b6196fb7a54aff6b5e3ecd00f7c0bab1b56eee39214b2b223a9d938c50af"}, {file = "Pillow-9.0.1-cp38-cp38-win32.whl", hash = "sha256:effb7749713d5317478bb3acb3f81d9d7c7f86726d41c1facca068a04cf5bb4c"},
{file = "Pillow-9.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98cb63ca63cb61f594511c06218ab4394bf80388b3d66cd61d0b1f63ee0ea69f"}, {file = "Pillow-9.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:7f7609a718b177bf171ac93cea9fd2ddc0e03e84d8fa4e887bdfc39671d46b00"},
{file = "Pillow-9.0.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc462d24500ba707e9cbdef436c16e5c8cbf29908278af053008d9f689f56dee"}, {file = "Pillow-9.0.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:80ca33961ced9c63358056bd08403ff866512038883e74f3a4bf88ad3eb66838"},
{file = "Pillow-9.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3586e12d874ce2f1bc875a3ffba98732ebb12e18fb6d97be482bd62b56803281"}, {file = "Pillow-9.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c3c33ac69cf059bbb9d1a71eeaba76781b450bc307e2291f8a4764d779a6b28"},
{file = "Pillow-9.0.0-cp39-cp39-win32.whl", hash = "sha256:68e06f8b2248f6dc8b899c3e7ecf02c9f413aab622f4d6190df53a78b93d97a5"}, {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:12875d118f21cf35604176872447cdb57b07126750a33748bac15e77f90f1f9c"},
{file = "Pillow-9.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:6579f9ba84a3d4f1807c4aab4be06f373017fc65fff43498885ac50a9b47a553"}, {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:514ceac913076feefbeaf89771fd6febde78b0c4c1b23aaeab082c41c694e81b"},
{file = "Pillow-9.0.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:47f5cf60bcb9fbc46011f75c9b45a8b5ad077ca352a78185bd3e7f1d294b98bb"}, {file = "Pillow-9.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3c5c79ab7dfce6d88f1ba639b77e77a17ea33a01b07b99840d6ed08031cb2a7"},
{file = "Pillow-9.0.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fd8053e1f8ff1844419842fd474fc359676b2e2a2b66b11cc59f4fa0a301315"}, {file = "Pillow-9.0.1-cp39-cp39-win32.whl", hash = "sha256:718856856ba31f14f13ba885ff13874be7fefc53984d2832458f12c38205f7f7"},
{file = "Pillow-9.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c5439bfb35a89cac50e81c751317faea647b9a3ec11c039900cd6915831064d"}, {file = "Pillow-9.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:f25ed6e28ddf50de7e7ea99d7a976d6a9c415f03adcaac9c41ff6ff41b6d86ac"},
{file = "Pillow-9.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95545137fc56ce8c10de646074d242001a112a92de169986abd8c88c27566a05"}, {file = "Pillow-9.0.1-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:011233e0c42a4a7836498e98c1acf5e744c96a67dd5032a6f666cc1fb97eab97"},
{file = "Pillow-9.0.0.tar.gz", hash = "sha256:ee6e2963e92762923956fe5d3479b1fdc3b76c83f290aad131a2f98c3df0593e"}, {file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:253e8a302a96df6927310a9d44e6103055e8fb96a6822f8b7f514bb7ef77de56"},
{file = "Pillow-9.0.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6295f6763749b89c994fcb6d8a7f7ce03c3992e695f89f00b741b4580b199b7e"},
{file = "Pillow-9.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9f44cd7e162ac6191491d7249cceb02b8116b0f7e847ee33f739d7cb1ea1f70"},
{file = "Pillow-9.0.1.tar.gz", hash = "sha256:6c8bc8238a7dfdaf7a75f5ec5a663f4173f8c367e5a39f87e720495e1eed75fa"},
] ]
platformdirs = [ platformdirs = [
{file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"}, {file = "platformdirs-2.5.0-py3-none-any.whl", hash = "sha256:30671902352e97b1eafd74ade8e4a694782bd3471685e78c32d0fdfd3aa7e7bb"},
{file = "platformdirs-2.4.1.tar.gz", hash = "sha256:440633ddfebcc36264232365d7840a970e75e1018d15b4327d11f91909045fda"}, {file = "platformdirs-2.5.0.tar.gz", hash = "sha256:8ec11dfba28ecc0715eb5fb0147a87b1bf325f349f3da9aab2cd6b50b96b692b"},
] ]
pluggy = [ pluggy = [
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
@ -1368,8 +1444,8 @@ toml = [
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
] ]
tomli = [ tomli = [
{file = "tomli-2.0.0-py3-none-any.whl", hash = "sha256:b5bde28da1fed24b9bd1d4d2b8cba62300bfb4ec9a6187a957e8ddb9434c5224"}, {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.0.tar.gz", hash = "sha256:c292c34f58502a1eb2bbb9f5bbc9a5ebc37bee10ffb8c2d6bbdfa8eb13cc14e1"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
] ]
tweepy = [ tweepy = [
{file = "tweepy-4.5.0-py2.py3-none-any.whl", hash = "sha256:1efe228d5994e0d996577bd052b73c59dada96ff8045e176bf46c175afe61859"}, {file = "tweepy-4.5.0-py2.py3-none-any.whl", hash = "sha256:1efe228d5994e0d996577bd052b73c59dada96ff8045e176bf46c175afe61859"},
@ -1431,6 +1507,10 @@ ulid-py = [
{file = "ulid-py-1.1.0.tar.gz", hash = "sha256:dc6884be91558df077c3011b9fb0c87d1097cb8fc6534b11f310161afd5738f0"}, {file = "ulid-py-1.1.0.tar.gz", hash = "sha256:dc6884be91558df077c3011b9fb0c87d1097cb8fc6534b11f310161afd5738f0"},
{file = "ulid_py-1.1.0-py2.py3-none-any.whl", hash = "sha256:b56a0f809ef90d6020b21b89a87a48edc7c03aea80e5ed5174172e82d76e3987"}, {file = "ulid_py-1.1.0-py2.py3-none-any.whl", hash = "sha256:b56a0f809ef90d6020b21b89a87a48edc7c03aea80e5ed5174172e82d76e3987"},
] ]
umongo = [
{file = "umongo-3.1.0-py2.py3-none-any.whl", hash = "sha256:f6913027651ae673d71aaf54285f9ebf1e49a3f57662e526d029ba72e1a3fcd5"},
{file = "umongo-3.1.0.tar.gz", hash = "sha256:20c72f09edae931285c22c1928862af35b90ec639a4dac2dbf015aaaac00e931"},
]
urllib3 = [ urllib3 = [
{file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"}, {file = "urllib3-1.26.8-py2.py3-none-any.whl", hash = "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed"},
{file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"}, {file = "urllib3-1.26.8.tar.gz", hash = "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c"},

View file

@ -7,7 +7,7 @@ authors = ["Zevaryx <zevaryx@gmail.com>"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = "^3.10"
PyYAML = "^6.0" PyYAML = "^6.0"
dis-snek = "^5.0.0" dis-snek = "*"
GitPython = "^3.1.26" GitPython = "^3.1.26"
mongoengine = "^0.23.1" mongoengine = "^0.23.1"
opencv-python = "^4.5.5" opencv-python = "^4.5.5"
@ -17,6 +17,8 @@ python-gitlab = "^3.1.1"
ulid-py = "^1.1.0" ulid-py = "^1.1.0"
tweepy = "^4.5.0" tweepy = "^4.5.0"
orjson = "^3.6.6" orjson = "^3.6.6"
jarvis-core = {git = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git", rev = "main"}
aiohttp = "^3.8.1"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
python-lsp-server = {extras = ["all"], version = "^1.3.3"} python-lsp-server = {extras = ["all"], version = "^1.3.3"}