Add calculator cog for math and conversions

This commit is contained in:
Zeva Rose 2022-12-28 08:18:35 +00:00
parent e8a419b9e3
commit 97d15f2f6b
6 changed files with 784 additions and 99 deletions

View file

@ -22,7 +22,7 @@ repos:
rev: 22.3.0
hooks:
- id: black
args: [--line-length=100, --target-version=py310]
args: [--line-length=120, --target-version=py310]
language_version: python3.10
- repo: https://github.com/pre-commit/mirrors-isort

417
jarvis/cogs/calc.py Normal file
View file

@ -0,0 +1,417 @@
"""JARVIS Calculator Cog."""
import json
from aiohttp import ClientSession
from calculator import calculate
from naff import AutocompleteContext, Client, Extension, InteractionContext
from naff.models.discord.components import Button
from naff.models.discord.embed import Embed, EmbedField
from naff.models.discord.enums import ButtonStyles
from naff.models.naff.application_commands import (
OptionTypes,
SlashCommand,
SlashCommandChoice,
slash_option,
)
from thefuzz import process
from jarvis.data import units
from jarvis.utils import build_embed
TEMP_CHOICES = (
SlashCommandChoice(name="Fahrenheit", value=0),
SlashCommandChoice(name="Celsius", value=1),
SlashCommandChoice(name="Kelvin", value=2),
)
TEMP_LOOKUP = {0: "F", 1: "C", 2: "K"}
CURRENCIES = (
"AUD",
"BGN",
"BRL",
"CAD",
"CHF",
"CNY",
"CZK",
"DKK",
"GBP",
"HKD",
"HRK",
"HUF",
"IDR",
"INR",
"ISK",
"JPY",
"KRW",
"MXN",
"MYR",
"NOK",
"NZD",
"PHP",
"PLN",
"RON",
"SEK",
"SGD",
"THB",
"TRY",
"USD",
"ZAR",
)
class CalcCog(Extension):
"""Calculator functions for JARVIS"""
def __init__(self, bot: Client):
self.bot = bot
async def _get_currency_conversion(self, from_: str, to: str) -> int:
"""Get the conversion rate."""
async with ClientSession() as session:
async with session.get("https://theforexapi.com/api/latest", params={"base": from_, "symbols": to}) as resp:
raw = await resp.content.read()
data = json.loads(raw.decode("UTF8"))
return data["rates"][to]
calc = SlashCommand(name="calc", description="Calculate some things")
@calc.subcommand(sub_cmd_name="math", sub_cmd_description="Do a basic math calculation")
@slash_option(name="expression", description="Expression to calculate", required=True, opt_type=OptionTypes.STRING)
async def _calc_math(self, ctx: InteractionContext, expression: str) -> None:
if expression == "The answer to life, the universe, and everything":
fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(42)))
embed = build_embed(title="Calculator", description=None, fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
return
try:
value = calculate(expression)
except Exception as e:
await ctx.send(f"Failed to calculate:\n{e}", ephemeral=True)
return
if not value:
await ctx.send("No value? Try a valid expression", ephemeral=True)
return
fields = (EmbedField(name="Expression", value=f"`{expression}`"), EmbedField(name="Result", value=str(value)))
embed = build_embed(title="Calculator", description=None, fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
convert = calc.group(name="convert", description="Conversion helpers")
@convert.subcommand(sub_cmd_name="temperature", sub_cmd_description="Convert between temperatures")
@slash_option(name="value", description="Value to convert", required=True, opt_type=OptionTypes.NUMBER)
@slash_option(
name="from_unit", description="From unit", required=True, opt_type=OptionTypes.INTEGER, choices=TEMP_CHOICES
)
@slash_option(
name="to_unit", description="To unit", required=True, opt_type=OptionTypes.INTEGER, choices=TEMP_CHOICES
)
async def _calc_convert_temperature(
self, ctx: InteractionContext, value: int, from_unit: int, to_unit: int
) -> None:
if from_unit == to_unit:
converted = value
elif from_unit == 0:
converted = (value - 32) * (5 / 9)
if to_unit == 2:
converted += 273.15
elif from_unit == 1:
if to_unit == 0:
converted = (value * 9 / 5) + 32
else:
converted = value + 273.15
else:
converted = value + 273.15
if to_unit == 0:
converted = (value * 9 / 5) + 32
fields = (
EmbedField(name=f"°{TEMP_LOOKUP.get(from_unit)}", value=f"{value:0.2f}"),
EmbedField(name=f"°{TEMP_LOOKUP.get(to_unit)}", value=f"{converted:0.2f}"),
)
embed = build_embed(
title="Conversion",
description=f"°{TEMP_LOOKUP.get(from_unit)} -> °{TEMP_LOOKUP.get(to_unit)}",
fields=fields,
)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
@convert.subcommand(sub_cmd_name="currency", sub_cmd_description="Convert currency based on current rates")
@slash_option(name="value", description="Value of starting currency", required=True, opt_type=OptionTypes.NUMBER)
@slash_option(
name="from_currency",
description="Currency to convert from",
required=True,
opt_type=OptionTypes.STRING,
autocomplete=True,
)
@slash_option(
name="to_currency",
description="Currency to convert to",
required=True,
opt_type=OptionTypes.STRING,
autocomplete=True,
)
async def _calc_convert_currency(
self, ctx: InteractionContext, value: int, from_currency: str, to_currency: str
) -> None:
if from_currency == to_currency:
conv = value
else:
rate = await self._get_currency_conversion(from_currency, to_currency)
conv = value * rate
fields = (
EmbedField(name=from_currency, value=f"{value:0.2f}"),
EmbedField(name=to_currency, value=f"{conv:0.2f}"),
)
embed = build_embed(title="Conversion", description=f"{from_currency} -> {to_currency}", fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
async def _convert(self, ctx: InteractionContext, from_: str, to: str, value: int) -> Embed:
*_, which = ctx.invoked_name.split(" ")
which = getattr(units, which.capitalize(), None)
ratio = which.get_rate(from_, to)
converted = value / ratio
fields = (EmbedField(name=from_, value=f"{value:0.2f}"), EmbedField(name=to, value=f"{converted:0.2f}"))
embed = build_embed(title="Conversion", description=f"{from_} -> {to}", fields=fields)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
@convert.subcommand(sub_cmd_name="angle", sub_cmd_description="Convert angles")
@slash_option(name="value", description="Angle to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_angle(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="area", sub_cmd_description="Convert areas")
@slash_option(name="value", description="Area to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_area(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="data", sub_cmd_description="Convert data sizes")
@slash_option(name="value", description="Data size to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_data(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="energy", sub_cmd_description="Convert energy")
@slash_option(name="value", description="Energy to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_energy(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="length", sub_cmd_description="Convert lengths")
@slash_option(name="value", description="Length to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_length(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="power", sub_cmd_description="Convert powers")
@slash_option(name="value", description="Power to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_power(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="pressure", sub_cmd_description="Convert pressures")
@slash_option(name="value", description="Pressure to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_pressure(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="speed", sub_cmd_description="Convert speeds")
@slash_option(name="value", description="Speed to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_speed(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="time", sub_cmd_description="Convert times")
@slash_option(name="value", description="Time to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_time(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="volume", sub_cmd_description="Convert volumes")
@slash_option(name="value", description="Volume to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_volume(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
@convert.subcommand(sub_cmd_name="weight", sub_cmd_description="Convert weights")
@slash_option(name="value", description="Weight to convert", opt_type=OptionTypes.NUMBER, required=True)
@slash_option(
name="from_unit",
description="Units to convert from",
opt_type=OptionTypes.STRING,
required=True,
autocomplete=True,
)
@slash_option(
name="to_unit", description="Units to convert to", opt_type=OptionTypes.STRING, required=True, autocomplete=True
)
async def _calc_convert_weight(self, ctx: InteractionContext, value: int, from_unit: str, to_unit: str) -> None:
await self._convert(ctx, from_unit, to_unit, value)
def _unit_autocomplete(self, which: units.Converter, unit: str) -> list[dict[str, str]]:
options = list(which.CONVERSIONS.keys())
results = process.extract(unit, options, limit=25)
if any([r[1] > 0 for r in results]):
return [{"name": r[0], "value": r[0]} for r in results if r[1] > 50]
return [{"name": r[0], "value": r[0]} for r in results]
@_calc_convert_angle.autocomplete("from_unit")
@_calc_convert_area.autocomplete("from_unit")
@_calc_convert_data.autocomplete("from_unit")
@_calc_convert_energy.autocomplete("from_unit")
@_calc_convert_length.autocomplete("from_unit")
@_calc_convert_power.autocomplete("from_unit")
@_calc_convert_pressure.autocomplete("from_unit")
@_calc_convert_speed.autocomplete("from_unit")
@_calc_convert_time.autocomplete("from_unit")
@_calc_convert_volume.autocomplete("from_unit")
@_calc_convert_weight.autocomplete("from_unit")
async def _autocomplete_from_unit(
self, ctx: AutocompleteContext, from_unit: str, to_unit: str = None, value: int = 0
) -> None:
*_, which = ctx.invoked_name.split(" ")
which = getattr(units, which.capitalize(), None)
await ctx.send(choices=self._unit_autocomplete(which, from_unit))
@_calc_convert_angle.autocomplete("to_unit")
@_calc_convert_area.autocomplete("to_unit")
@_calc_convert_data.autocomplete("to_unit")
@_calc_convert_energy.autocomplete("to_unit")
@_calc_convert_length.autocomplete("to_unit")
@_calc_convert_power.autocomplete("to_unit")
@_calc_convert_pressure.autocomplete("to_unit")
@_calc_convert_speed.autocomplete("to_unit")
@_calc_convert_time.autocomplete("to_unit")
@_calc_convert_volume.autocomplete("to_unit")
@_calc_convert_weight.autocomplete("to_unit")
async def _autocomplete_to_unit(
self, ctx: AutocompleteContext, from_unit: str, to_unit: str = None, value: int = 0
) -> None:
*_, which = ctx.invoked_name.split(" ")
which = getattr(units, which.capitalize(), None)
await ctx.send(choices=self._unit_autocomplete(which, to_unit))
def _currency_autocomplete(self, currency: str) -> list[dict[str, str]]:
results = process.extract(currency, CURRENCIES, limit=25)
if any([r[1] > 0 for r in results]):
return [{"name": r[0], "value": r[0]} for r in results if r[1] > 50]
return [{"name": r[0], "value": r[0]} for r in results]
@_calc_convert_currency.autocomplete("from_currency")
async def _autocomplete_from_currency(
self, ctx: AutocompleteContext, from_currency: str = None, to_currency: str = None, value: int = 0
) -> None:
await ctx.send(choices=self._currency_autocomplete(from_currency))
@_calc_convert_currency.autocomplete("to_currency")
async def _autocomplete_to_currency(
self, ctx: AutocompleteContext, from_currency: str = None, to_currency: str = None, value: int = 0
) -> None:
await ctx.send(choices=self._currency_autocomplete(to_currency))
def setup(bot: Client) -> None:
"""Add CalcCog to JARVIS"""
CalcCog(bot)

View file

@ -3,6 +3,7 @@ import logging
import re
import secrets
import string
import urllib.parse
from datetime import datetime, timezone
from io import BytesIO
@ -57,7 +58,9 @@ class UtilCog(Extension):
if ctx.author.id == 264072583987593217:
await ctx.send("Oh fuck no, go fuck yourself")
elif ctx.author.id == 840031256201003008:
await ctx.send("https://tenor.com/view/fluffy-gabriel-iglesias-you-need-jesus-thats-what-you-need-pointing-up-gif-16385108")
await ctx.send(
"https://tenor.com/view/fluffy-gabriel-iglesias-you-need-jesus-thats-what-you-need-pointing-up-gif-16385108"
)
elif ctx.author.id == 215564028615852033:
await ctx.send("As flattered as I am, I'm not into bestiality")
else:
@ -83,26 +86,14 @@ class UtilCog(Extension):
inline=True,
)
)
fields.append(
EmbedField(name="NAFF", value=f"[{const.__version__}](https://naff.info)", inline=True)
)
repo_url = (
f"https://git.zevaryx.com/stark-industries/jarvis/jarvis-bot/-/tree/{get_repo_hash()}"
)
fields.append(
EmbedField(name="Git Hash", value=f"[{get_repo_hash()[:7]}]({repo_url})", inline=True)
)
fields.append(EmbedField(name="NAFF", value=f"[{const.__version__}](https://naff.info)", inline=True))
repo_url = f"https://git.zevaryx.com/stark-industries/jarvis/jarvis-bot/-/tree/{get_repo_hash()}"
fields.append(EmbedField(name="Git Hash", value=f"[{get_repo_hash()[:7]}]({repo_url})", inline=True))
fields.append(EmbedField(name="Online Since", value=f"<t:{uptime}:F>", inline=False))
num_domains = len(self.bot.phishing_domains)
fields.append(
EmbedField(
name="Phishing Protection", value=f"Detecting {num_domains} phishing domains"
)
)
fields.append(EmbedField(name="Phishing Protection", value=f"Detecting {num_domains} phishing domains"))
embed = build_embed(title=title, description=desc, fields=fields, color=color)
components = Button(
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
@bot.subcommand(
@ -115,9 +106,7 @@ class UtilCog(Extension):
JARVIS_LOGO.save(image_bytes, "PNG")
image_bytes.seek(0)
logo = File(image_bytes, file_name="logo.png")
components = Button(
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(file=logo, components=components)
rc = SlashCommand(name="rc", description="Robot Camo emoji commands")
@ -163,9 +152,7 @@ class UtilCog(Extension):
embed = build_embed(title="Avatar", description="", fields=[], color="#00FFEE")
embed.set_image(url=avatar)
embed.set_author(name=f"{user.username}#{user.discriminator}", icon_url=avatar)
components = Button(
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
@slash_command(
@ -213,9 +200,7 @@ class UtilCog(Extension):
im.save(image_bytes, "PNG")
image_bytes.seek(0)
color_show = File(image_bytes, file_name="color_show.png")
components = Button(
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, file=color_show, components=components)
@slash_command(name="avatar", description="Get a user avatar")
@ -281,11 +266,15 @@ class UtilCog(Extension):
)
embed.set_thumbnail(url=user.display_avatar.url)
embed.set_footer(text=f"ID: {user.id}")
components = Button(
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
@slash_command(name="lmgtfy", description="Let me Google that for you")
@slash_option(name="search", description="What to search", opt_type=OptionTypes.STRING, required=True)
async def _lmgtfy(self, ctx: InteractionContext, search: str) -> None:
url = "https://letmegooglethat.com/?q=" + urllib.parse.quote_plus(search)
await ctx.send(url)
@slash_command(
name="userinfo",
description="Get user info",
@ -338,9 +327,7 @@ class UtilCog(Extension):
embed.set_author(name=guild.name, icon_url=guild.icon.url)
embed.set_thumbnail(url=guild.icon.url)
embed.set_footer(text=f"ID: {guild.id} | Server Created")
components = Button(
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, components=components)
@slash_command(
@ -389,9 +376,7 @@ class UtilCog(Extension):
)
@slash_command(name="pigpen", description="Encode a string into pigpen")
@slash_option(
name="text", description="Text to encode", opt_type=OptionTypes.STRING, required=True
)
@slash_option(name="text", description="Text to encode", opt_type=OptionTypes.STRING, required=True)
async def _pigpen(self, ctx: InteractionContext, text: str) -> None:
outp = "`"
for c in text:
@ -406,15 +391,9 @@ class UtilCog(Extension):
outp += "`"
await ctx.send(outp[:2000])
@slash_command(
name="timestamp", description="Convert a datetime or timestamp into it's counterpart"
)
@slash_option(
name="string", description="String to convert", opt_type=OptionTypes.STRING, required=True
)
@slash_option(
name="private", description="Respond quietly?", opt_type=OptionTypes.BOOLEAN, required=False
)
@slash_command(name="timestamp", description="Convert a datetime or timestamp into it's counterpart")
@slash_option(name="string", description="String to convert", opt_type=OptionTypes.STRING, required=True)
@slash_option(name="private", description="Respond quietly?", opt_type=OptionTypes.BOOLEAN, required=False)
async def _timestamp(self, ctx: InteractionContext, string: str, private: bool = False) -> None:
timestamp = parse(string)
if not timestamp:
@ -436,9 +415,7 @@ class UtilCog(Extension):
EmbedField(name="ISO8601", value=timestamp.isoformat()),
]
embed = build_embed(title="Converted Time", description=f"`{string}`", fields=fields)
components = Button(
style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}"
)
components = Button(style=ButtonStyles.DANGER, emoji="🗑️", custom_id=f"delete|{ctx.author.id}")
await ctx.send(embeds=embed, ephemeral=private, components=components)
@bot.subcommand(sub_cmd_name="support", sub_cmd_description="Got issues?")
@ -453,9 +430,7 @@ We'll help as best we can with whatever issues you encounter.
"""
)
@bot.subcommand(
sub_cmd_name="privacy_terms", sub_cmd_description="View Privacy and Terms of Use"
)
@bot.subcommand(sub_cmd_name="privacy_terms", sub_cmd_description="View Privacy and Terms of Use")
async def _privacy_terms(self, ctx: InteractionContext) -> None:
await ctx.send(
"""

241
jarvis/data/units.py Normal file
View file

@ -0,0 +1,241 @@
"""
Unit Converter utilities.
Rates based on https://github.com/microsoft/calculator
"""
from dataclasses import dataclass, field
@dataclass
class Converter:
BASE: str = "sample"
CONVERSIONS: dict[str, int] = field(default_factory=dict)
@classmethod
def get_rate(cls, from_: str, to: str) -> int:
"""
Get the conversion rate
Args:
from_: Convert from this
to: Convert to this
"""
if from_ == cls.BASE:
return cls.CONVERSIONS.get(to, None)
else:
from_rate = cls.CONVERSIONS.get(from_)
to_rate = cls.CONVERSIONS.get(to)
return (1 / from_rate) * to_rate
class Angle(Converter):
BASE = "degree"
CONVERSIONS = {"degree": 1, "radian": 57.29577951308233, "gradian": 0.9}
class Area(Converter):
BASE = "square meter"
CONVERSIONS = {
"acre": 4046.8564224,
"square meter": 1,
"square foot": 0.09290304,
"square yard": 0.83612736,
"square millimeter": 0.000001,
"square centimeter": 0.00001,
"square inch": 0.00064516,
"square mile": 2589988.110336,
"square kilometer": 1000000,
"hectare": 10000,
"hand": 0.01251604,
"paper": 0.06032246,
"soccer field": 10869.66,
"castle": 100000,
"pyeong": 400 / 121,
}
class Data(Converter):
BASE = "megabyte"
CONVERSIONS = {
"bit": 0.000000125,
"byte": 0.000001,
"kilobyte": 0.001,
"megabyte": 1,
"gigabyte": 1000,
"terabyte": 1000000,
"petabyte": 1000000000,
"exabyte": 1000000000000,
"zetabyte": 1000000000000000,
"yottabyte": 1000000000000000000,
"kilobit": 0.000125,
"megabit": 0.0125,
"gigabit": 125,
"terabit": 125000,
"petabit": 125000000,
"exabit": 125000000000,
"zetabit": 125000000000000,
"yottabit": 125000000000000000,
"gibibit": 134.217728,
"gibibyte": 1073.731824,
"kibibit": 0.000128,
"kibibyte": 0.001024,
"mebibit": 0.131072,
"mebibyte": 1.048576,
"pebibit": 140737488.355328,
"pebibyte": 1125899906.842624,
"tebibit": 137438.953472,
"tebibyte": 1099511.627776,
"exbibit": 144115188075.855872,
"exbibyte": 1152921504606.846976,
"zebibit": 147573952589676.412928,
"zebibyte": 1180591620717411.303424,
"yobibit": 151115727451828646.838272,
"yobibyte": 1208925819614629174.706176,
"floppy disk": 1.474560,
"cd": 734.003200,
"dvd": 5046.586573,
}
class Energy(Converter):
BASE = "joule"
CONVERSIONS = {
"calorie": 4.184,
"kilocalorie": 4184,
"british thermal unit": 1055.056,
"kilojoule": 1000,
"electron volt": 0.0000000000000000001602176565,
"joule": 1,
"foot pound": 1.3558179483314,
"battery": 9000,
"banana": 439614,
"slice of cake": 1046700,
}
class Length(Converter):
BASE = "meter"
CONVERSIONS = {
"inch": 0.0254,
"foot": 0.3048,
"yard": 0.9144,
"mile": 1609.344,
"micron": 0.000001,
"millimeter": 0.001,
"nanometer": 0.000000001,
"centimeter": 0.01,
"meter": 1,
"kilometer": 1000,
"nautical mile": 1852,
"paperclip": 0.035052,
"hand": 0.18669,
"jumbo jet": 76,
}
class Power(Converter):
BASE = "watt"
CONVERSIONS = {
"british thermal unit per minute": 17.58426666666667,
"foot pound per minute": 0.0225969658055233,
"watt": 1,
"kilowatt": 1000,
"horsepower": 745.69987158227022,
"lightbulb": 60,
"horse": 745.7,
"train engine": 2982799.486329081,
}
class Pressure(Converter):
BASE = "atmosphere"
CONVERSIONS = {
"atmosphere": 1,
"bar": 0.9869232667160128,
"kilopascal": 0.0098692326671601,
"millimeter of mercury": 0.0013155687145324,
"pascal": 9.869232667160128e-6,
"psi": 0.068045961016531,
}
class Speed(Converter):
BASE = "centimeters per second"
CONVERSIONS = {
"centimeters per second": 1,
"feet per second": 30.48,
"kilometers per hour": 27.777777777777777777778,
"knot": 51.44,
"mach": 34040,
"meters per second": 100,
"miles per hour": 44.7,
"turtle": 8.94,
"horse": 2011.5,
"jet": 24585,
}
class Time(Converter):
BASE = "second"
CONVERSIONS = {
"day": 86400,
"second": 1,
"week": 604800,
"millisecond": 0.001,
"microsecond": 0.000001,
"minute": 60,
"hour": 3600,
}
class Volume(Converter):
BASE = "millileter"
CONVERSIONS = {
"cup (US)": 236.588237,
"pint (US)": 473.176473,
"pint (UK)": 568.26125,
"quart (US)": 946.352946,
"quart (UK)": 1136.5225,
"gallon (US)": 3785.411784,
"gallon (UK)": 4546.09,
"liter": 1000,
"teaspoon (US)": 4.92892159375,
"tablespoon (US)": 14.78676478125,
"cubic centimeter": 1,
"cubic yard": 764554.857984,
"cubic meter": 1000000,
"millimeter": 1,
"cubic inch": 16.387064,
"cubic foot": 28316.846592,
"fluid ounce (US)": 29.5735295625,
"fluid ounce (UK)": 28.4130625,
"teaspoon (UK)": 5.91938802083333333333,
"tablespoon (UK)": 17.7581640625,
"coffee cup": 236.588237,
"bathtub": 378541.2,
"swimming pool": 3750000000,
}
class Weight(Converter):
BASE = "kilogram"
CONVERSIONS = {
"kilogram": 1,
"hectogram": 0.1,
"decagram": 0.01,
"gram": 0.001,
"pound": 0.45359237,
"ounce": 0.028349523125,
"milligram": 0.000001,
"centigram": 0.00001,
"decigram": 0.0001,
"long ton": 1016.0469088,
"tonne": 1000,
"stone": 6.35029318,
"carat": 0.0002,
"short ton": 907.18474,
"snowflake": 0.000002,
"soccer ball": 0.4325,
"elephant": 4000,
"whale": 90000,
}

145
poetry.lock generated
View file

@ -38,7 +38,7 @@ multidict = ">=4.5,<7.0"
yarl = ">=1.0,<2.0"
[package.extras]
speedups = ["aiodns", "brotli", "cchardet"]
speedups = ["Brotli", "aiodns", "cchardet"]
[[package]]
name = "aioredis"
@ -154,7 +154,7 @@ update-checker = ">=0.18"
[package.extras]
ci = ["coveralls"]
dev = ["packaging", "pre-commit", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-trio", "asynctest (>=0.13.0)", "mock (>=0.8)", "pytest (>=2.7.3)", "pytest-asyncio", "pytest-vcr", "testfixtures (>4.13.2,<7)", "vcrpy (==4.1.1)"]
dev = ["asynctest (>=0.13.0)", "mock (>=0.8)", "packaging", "pre-commit", "pytest (>=2.7.3)", "pytest-asyncio", "pytest-vcr", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-trio", "testfixtures (>4.13.2,<7)", "vcrpy (==4.1.1)"]
lint = ["pre-commit", "sphinx", "sphinx-rtd-theme", "sphinxcontrib-trio"]
readthedocs = ["sphinx", "sphinx-rtd-theme", "sphinxcontrib-trio"]
test = ["asynctest (>=0.13.0)", "mock (>=0.8)", "pytest (>=2.7.3)", "pytest-asyncio", "pytest-vcr", "testfixtures (>4.13.2,<7)", "vcrpy (==4.1.1)"]
@ -172,10 +172,10 @@ aiohttp = "*"
yarl = "*"
[package.extras]
test = ["vcrpy (==4.0.2)", "testfixtures (>4.13.2,<7)", "pytest-vcr", "pytest", "mock (>=0.8)", "asynctest (>=0.13.0)"]
lint = ["pydocstyle", "pre-commit", "flynt", "flake8", "black"]
dev = ["vcrpy (==4.0.2)", "testfixtures (>4.13.2,<7)", "pytest-vcr", "pytest", "mock (>=0.8)", "asynctest (>=0.13.0)", "pydocstyle", "pre-commit", "flynt", "flake8", "black"]
ci = ["coveralls"]
dev = ["asynctest (>=0.13.0)", "black", "flake8", "flynt", "mock (>=0.8)", "pre-commit", "pydocstyle", "pytest", "pytest-vcr", "testfixtures (>4.13.2,<7)", "vcrpy (==4.0.2)"]
lint = ["black", "flake8", "flynt", "pre-commit", "pydocstyle"]
test = ["asynctest (>=0.13.0)", "mock (>=0.8)", "pytest", "pytest-vcr", "testfixtures (>4.13.2,<7)", "vcrpy (==4.0.2)"]
[[package]]
name = "attrs"
@ -186,10 +186,10 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.extras]
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "sphinx", "sphinx-notfound-page", "zope.interface"]
docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "zope.interface"]
tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six"]
[[package]]
name = "beautifulsoup4"
@ -251,6 +251,21 @@ python-versions = ">=3.5.*, <4"
[package.extras]
develop = ["aiomisc", "pytest", "pytest-cov"]
[[package]]
name = "calculator"
version = "1.0.0"
description = "A simple calculator"
category = "main"
optional = false
python-versions = ">=3.10"
develop = false
[package.source]
type = "git"
url = "https://git.zevaryx.com/zevaryx/calculator.git"
reference = "HEAD"
resolved_reference = "b317d35788c6a06f2b496844d5fdf4e3414453e6"
[[package]]
name = "certifi"
version = "2021.10.8"
@ -268,7 +283,7 @@ optional = false
python-versions = ">=3.5.0"
[package.extras]
unicode_backport = ["unicodedata2"]
unicode-backport = ["unicodedata2"]
[[package]]
name = "click"
@ -306,7 +321,7 @@ optional = false
python-versions = "*"
[package.extras]
test = ["hypothesis (==3.55.3)", "flake8 (==3.7.8)"]
test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
[[package]]
name = "dateparser"
@ -323,9 +338,9 @@ regex = "<2019.02.19 || >2019.02.19,<2021.8.27 || >2021.8.27,<2022.3.15"
tzlocal = "*"
[package.extras]
langdetect = ["langdetect"]
calendars = ["convertdate", "convertdate", "hijri-converter"]
fasttext = ["fasttext"]
calendars = ["convertdate", "hijri-converter", "convertdate"]
langdetect = ["langdetect"]
[[package]]
name = "discord-typings"
@ -412,13 +427,13 @@ python-versions = ">=3.7"
zipp = ">=0.5"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"]
perf = ["ipython"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
[[package]]
name = "jarvis-core"
version = "0.13.1"
version = "0.16.0"
description = "JARVIS core"
category = "main"
optional = false
@ -430,6 +445,7 @@ aiohttp = "^3.8.1"
motor = "^2.5.1"
nanoid = "^2.0.0"
orjson = "^3.6.6"
python-dotenv = "^0.21.0"
pytz = "^2022.1"
PyYAML = "^6.0"
rich = "^12.3.0"
@ -439,7 +455,7 @@ umongo = "^3.1.0"
type = "git"
url = "https://git.zevaryx.com/stark-industries/jarvis/jarvis-core.git"
reference = "main"
resolved_reference = "739d07885e161d66adbf946805e70b88360ddce3"
resolved_reference = "1eb9455d800bc33fd45142d8ffeea56a99dad813"
[[package]]
name = "jinxed"
@ -467,7 +483,7 @@ ovld = ">=0.3.1,<0.4.0"
watchdog = ">=1.0.2"
[package.extras]
develoop = ["hrepr (>=0.4.0,<0.5.0)", "rich (>=10.13.0,<11.0.0)", "giving (>=0.3.6,<0.4.0)"]
develoop = ["giving (>=0.3.6,<0.4.0)", "hrepr (>=0.4.0,<0.5.0)", "rich (>=10.13.0,<11.0.0)"]
[[package]]
name = "marshmallow"
@ -481,9 +497,9 @@ python-versions = ">=3.7"
packaging = ">=17.0"
[package.extras]
dev = ["pytest", "pytz", "simplejson", "mypy (==0.960)", "flake8 (==4.0.1)", "flake8-bugbear (==22.4.25)", "pre-commit (>=2.4,<3.0)", "tox"]
docs = ["sphinx (==4.5.0)", "sphinx-issues (==3.0.1)", "alabaster (==0.7.12)", "sphinx-version-warning (==1.1.2)", "autodocsumm (==0.2.8)"]
lint = ["mypy (==0.960)", "flake8 (==4.0.1)", "flake8-bugbear (==22.4.25)", "pre-commit (>=2.4,<3.0)"]
dev = ["flake8 (==4.0.1)", "flake8-bugbear (==22.4.25)", "mypy (==0.960)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"]
docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.8)", "sphinx (==4.5.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"]
lint = ["flake8 (==4.0.1)", "flake8-bugbear (==22.4.25)", "mypy (==0.960)", "pre-commit (>=2.4,<3.0)"]
tests = ["pytest", "pytz", "simplejson"]
[[package]]
@ -529,7 +545,7 @@ python-versions = "*"
[[package]]
name = "naff"
version = "1.11.1"
version = "1.12.0"
description = "Not another freaking fork"
category = "main"
optional = false
@ -542,11 +558,11 @@ discord-typings = ">=0.5.1"
tomli = "*"
[package.extras]
all = ["PyNaCl (>=1.5.0,<1.6)", "aiodns", "orjson", "brotli", "sentry-sdk"]
docs = ["PyNaCl (>=1.5.0,<1.6)", "aiodns", "orjson", "brotli", "sentry-sdk", "mkdocs-autorefs", "mkdocs-awesome-pages-plugin", "mkdocs-material", "mkdocstrings-python", "mkdocs-minify-plugin", "mkdocs-git-committers-plugin-2", "mkdocs-git-revision-date-localized-plugin"]
all = ["Brotli", "PyNaCl (>=1.5.0,<1.6)", "aiodns", "orjson", "sentry-sdk"]
docs = ["Brotli", "PyNaCl (>=1.5.0,<1.6)", "aiodns", "mkdocs-autorefs", "mkdocs-awesome-pages-plugin", "mkdocs-git-committers-plugin-2", "mkdocs-git-revision-date-localized-plugin", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings-python", "orjson", "sentry-sdk"]
sentry = ["sentry-sdk"]
speedup = ["aiodns", "orjson", "brotli"]
tests = ["pytest", "pytest-recording", "pytest-asyncio", "pytest-cov", "typeguard"]
speedup = ["Brotli", "aiodns", "orjson"]
tests = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-recording", "python-dotenv", "typeguard"]
voice = ["PyNaCl (>=1.5.0,<1.6)"]
[[package]]
@ -567,7 +583,7 @@ uvicorn = "^0.18.2"
type = "git"
url = "https://github.com/artem30801/nafftrack.git"
reference = "master"
resolved_reference = "eae6ffd93a1a7854347eb0e147b894bf307c0003"
resolved_reference = "ac5ece577f67faad01602d1b945e08c72f43d093"
[[package]]
name = "nanoid"
@ -661,11 +677,11 @@ python-versions = ">=3.10"
aiohttp = {version = "3.8.1", markers = "python_version >= \"3.6\""}
aiosignal = {version = "1.2.0", markers = "python_version >= \"3.6\""}
async-timeout = {version = "4.0.2", markers = "python_version >= \"3.6\""}
attrs = {version = "21.4.0", markers = "python_version >= \"3.6\" and python_full_version < \"3.0.0\" or python_full_version >= \"3.5.0\" and python_version >= \"3.6\""}
attrs = {version = "21.4.0", markers = "python_version >= \"3.6\""}
certifi = {version = "2021.10.8", markers = "python_version >= \"2.7\" and python_full_version < \"3.0.0\" or python_full_version >= \"3.6.0\""}
charset-normalizer = {version = "2.0.12", markers = "python_full_version >= \"3.6.0\" and python_version >= \"3.6\""}
charset-normalizer = {version = "2.0.12", markers = "python_version >= \"3.6\""}
frozenlist = {version = "1.3.0", markers = "python_version >= \"3.7\""}
idna = {version = "3.3", markers = "python_version >= \"3.6\" and python_full_version < \"3.0.0\" or python_full_version >= \"3.6.0\" and python_version >= \"3.6\""}
idna = {version = "3.3", markers = "python_version >= \"3.6\""}
multidict = {version = "6.0.2", markers = "python_version >= \"3.7\""}
pycryptodome = {version = "3.14.1", markers = "python_version >= \"2.7\" and python_full_version < \"3.0.0\" or python_full_version >= \"3.5.0\""}
requests = {version = "2.27.1", markers = "python_version >= \"2.7\" and python_full_version < \"3.0.0\" or python_full_version >= \"3.6.0\""}
@ -701,8 +717,8 @@ optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"]
test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"]
[[package]]
name = "prometheus-client"
@ -732,7 +748,7 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
test = ["ipaddress", "mock", "enum34", "pywin32", "wmi"]
test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
[[package]]
name = "pycryptodome"
@ -770,7 +786,7 @@ python-versions = "*"
aws = ["pymongo-auth-aws (<2.0.0)"]
encryption = ["pymongocrypt (>=1.1.0,<2.0.0)"]
gssapi = ["pykerberos"]
ocsp = ["pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)", "certifi"]
ocsp = ["certifi", "pyopenssl (>=17.2.0)", "requests (<3.0.0)", "service-identity (>=18.1.0)"]
snappy = ["python-snappy"]
srv = ["dnspython (>=1.16.0,<1.17.0)"]
tls = ["ipaddress"]
@ -815,6 +831,17 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
[package.dependencies]
six = ">=1.5"
[[package]]
name = "python-dotenv"
version = "0.21.0"
description = "Read key-value pairs from a .env file and set them as environment variables"
category = "main"
optional = false
python-versions = ">=3.7"
[package.extras]
cli = ["click (>=5.0)"]
[[package]]
name = "python-gitlab"
version = "3.5.0"
@ -839,6 +866,9 @@ category = "main"
optional = false
python-versions = "*"
[package.dependencies]
setuptools = "*"
[[package]]
name = "pytz"
version = "2022.1"
@ -890,7 +920,7 @@ urllib3 = ">=1.21.1,<1.27"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<5)"]
[[package]]
name = "requests-oauthlib"
@ -951,7 +981,20 @@ six = ">=1.13"
websocket-client = ">=0.56,<0.58 || >0.58,<0.59 || >0.59,<1.0 || >1.0,<1.1 || >1.1"
[package.extras]
ssl_backport = ["backports.ssl", "backports.ssl-match-hostname", "pyopenssl"]
ssl-backport = ["PyOpenSSL", "backports.ssl", "backports.ssl-match-hostname"]
[[package]]
name = "setuptools"
version = "65.6.3"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
category = "main"
optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "six"
@ -1065,7 +1108,7 @@ tzdata = {version = "*", markers = "platform_system == \"Windows\""}
[package.extras]
devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"]
test = ["pytest-mock (>=3.3)", "pytest (>=4.3)"]
test = ["pytest (>=4.3)", "pytest-mock (>=3.3)"]
[[package]]
name = "ulid-py"
@ -1118,7 +1161,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
[package.extras]
brotli = ["brotlipy (>=0.6.0)"]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)"]
socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
[[package]]
@ -1134,7 +1177,7 @@ click = ">=7.0"
h11 = ">=0.8"
[package.extras]
standard = ["websockets (>=10.0)", "httptools (>=0.4.0)", "watchfiles (>=0.13)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"]
standard = ["PyYAML (>=5.1)", "colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"]
[[package]]
name = "watchdog"
@ -1164,9 +1207,9 @@ optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["Sphinx (>=3.4)", "sphinx-rtd-theme (>=0.5)"]
optional = ["python-socks", "wsaccel"]
test = ["websockets"]
optional = ["wsaccel", "python-socks"]
docs = ["sphinx-rtd-theme (>=0.5)", "Sphinx (>=3.4)"]
[[package]]
name = "websockets"
@ -1197,13 +1240,13 @@ optional = false
python-versions = ">=3.7"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"]
testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
[metadata]
lock-version = "1.1"
python-versions = "^3.10"
content-hash = "e95b3b3bed46990e5d3bd4f8662fd888dbf35a9272f09a18192c78d6c60b6f83"
content-hash = "57bd23e6265cf41781732790f7aea43c6985f3711ecd9977f8058b81b2689460"
[metadata.files]
aiofile = [
@ -1386,6 +1429,7 @@ caio = [
{file = "caio-0.9.5-py3-none-any.whl", hash = "sha256:3c74d84dff2bec5f93685cf2f32eb22e4cc5663434a9be5f4a759247229b69b3"},
{file = "caio-0.9.5.tar.gz", hash = "sha256:167d9342a807bae441b2e88f9ecb62da2f236b319939a8679f68f510a0194c40"},
]
calculator = []
certifi = [
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
@ -1594,8 +1638,8 @@ mypy-extensions = [
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
naff = [
{file = "naff-1.11.1-py3-none-any.whl", hash = "sha256:ea9192556ad162e9990f41b1d4c315255e4354580614bdedc6ac4228c3339004"},
{file = "naff-1.11.1.tar.gz", hash = "sha256:f1933c218b3a3ac93866245f8d2b034cc8d2b4b4ff48b76cacd37a0c2507abe2"},
{file = "naff-1.12.0-py3-none-any.whl", hash = "sha256:37b595f0c9fed1672b5fe6f511374da4a33e818ae8451c710d745231d7cbd941"},
{file = "naff-1.12.0.tar.gz", hash = "sha256:21d1ce708e1a7cfe08ae59e7d79576cff103a027424b032c9ac8c33dbe2d0a5d"},
]
nafftrack = []
nanoid = [
@ -1949,7 +1993,6 @@ pymongo = [
{file = "pymongo-3.12.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0be605bfb8461384a4cb81e80f51eb5ca1b89851f2d0e69a75458c788a7263a4"},
{file = "pymongo-3.12.3-cp39-cp39-win32.whl", hash = "sha256:2157d68f85c28688e8b723bbe70c8013e0aba5570e08c48b3562f74d33fc05c4"},
{file = "pymongo-3.12.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfa217bf8cf3ff6b30c8e6a89014e0c0e7b50941af787b970060ae5ba04a4ce5"},
{file = "pymongo-3.12.3-py2.7-macosx-10.14-intel.egg", hash = "sha256:d81299f63dc33cc172c26faf59cc54dd795fc6dd5821a7676cca112a5ee8bbd6"},
{file = "pymongo-3.12.3.tar.gz", hash = "sha256:0a89cadc0062a5e53664dde043f6c097172b8c1c5f0094490095282ff9995a5f"},
]
pyparsing = [
@ -1964,6 +2007,10 @@ python-dateutil = [
{file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
{file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]
python-dotenv = [
{file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"},
{file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"},
]
python-gitlab = [
{file = "python-gitlab-3.5.0.tar.gz", hash = "sha256:29ae7fb9b8c9aeb2e6e19bd2fd04867e93ecd7af719978ce68fac0cf116ab30d"},
{file = "python_gitlab-3.5.0-py3-none-any.whl", hash = "sha256:73b5aa6502efa557ee1a51227cceb0243fac5529627da34f08c5f265bf50417c"},
@ -2135,6 +2182,10 @@ rook = [
{file = "rook-0.1.175-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eb2783d654093f9e8fa2508dd5ee29c9fff90ccb075ac06359b103dc849a18db"},
{file = "rook-0.1.175.tar.gz", hash = "sha256:b6d92298bfd170c8ff0e4b13ba870079f44644386e12c08244e182421b471004"},
]
setuptools = [
{file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"},
{file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"},
]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},

View file

@ -31,6 +31,7 @@ ansitoimg = "^2022.1"
nest-asyncio = "^1.5.5"
thefuzz = {extras = ["speedup"], version = "^0.19.0"}
beautifulsoup4 = "^4.11.1"
calculator = {git = "https://git.zevaryx.com/zevaryx/calculator.git"}
[tool.poetry.dev-dependencies]
black = {version = "^22.3.0", allow-prereleases = true}