<commit_before>
import discord
from discord.ext import commands

import asyncio
import concurrent.futures
import math
import multiprocessing

import sympy

from utilities import checks

def setup(bot):
	bot.add_cog(Math())

class Math(commands.Cog):
	
	'''
	Also see Matrix category
	'''
	
	async def cog_check(self, ctx):
		return await checks.not_forbidden().predicate(ctx)
	
	# Basic
	
	@commands.command()
	async def add(self, ctx, *numbers: float):
		'''Add numbers together'''
		if not numbers:
			await ctx.embed_reply("Add what?")
			return
		await ctx.embed_reply(f"{' + '.join(f'{number:g}' for number in numbers)} = {sum(numbers):g}")
	
	# TODO: Fix/Improve
	@commands.command(aliases = ["calc", "calculator"])
	async def calculate(self, ctx, *, equation: str):
		'''Calculator'''
		#_equation = re.sub("[^[0-9]+-/*^%\.]", "", equation).replace('^', "**") #words
		replacements = {"pi" : "math.pi", 'e' : "math.e", "sin" : "math.sin", 
                        "cos" : "math.cos", "tan" : "math.tan", '^' : "**"}
		allowed = set("0123456789.+-*/^%()")
		for key, value in replacements.items():
			equation = equation.replace(key, value)
		# TODO: use filter
		equation = "".join(character for character in equation if character in allowed)
		print("Calculated " + equation)
		with multiprocessing.Pool(1) as pool:
			async_result = pool.apply_async(eval, (equation,))
			future = ctx.bot.loop.run_in_executor(None, async_result.get, 10.0)
			try:
				result = await asyncio.wait_for(future, 10.0)
				await ctx.embed_reply(f"{equation} = {result}")
			except discord.HTTPException:
				# TODO: use textwrap/paginate
				await ctx.embed_reply(":no_entry: Output too long")
			except SyntaxError:
				await ctx.embed_reply(":no_entry: Syntax error")
			except TypeError as e:
				await ctx.embed_reply(f":no_entry: Error: {e}")
			except ZeroDivisionError:
				await ctx.embed_reply(":no_entry: Error: Division by zero")
			except (concurrent.futures.TimeoutError, multiprocessing.context.TimeoutError):
				await ctx.embed_reply(":no_entry: Execution exceeded time limit")
	
	@commands.command()
	async def exp(self, ctx, value: float):
		'''
		Exponential function
		e ** value | e ^ value
		'''
		try:
			await ctx.embed_reply(math.exp(value))
		except OverflowError as e:
			await ctx.embed_reply(f":no_entry: Error: {e}")
	
	@commands.command()
	async def factorial(self, ctx, value: int):
		'''Factorial'''
		try:
			await ctx.embed_reply(math.factorial(value))
		except OverflowError as e:
			await ctx.embed_reply(f":no_entry: Error: {e}")
	
	@commands.command(aliases = ["greatest_common_divisor"])
	async def gcd(self, ctx, value_a: int, value_b: int):
		'''Greatest common divisor'''
		await ctx.embed_reply(math.gcd(value_a, value_b))
	
	@commands.command(aliases = ['π'])
	async def pi(self, ctx, digits: int = 3, start: int = 1):
		'''Digits of pi'''
		# Handle decimal point being considered digit
		if start <= 1:
			start = 0
			# Don't exceed 1000 digit limit
			if 1 < digits < 1000:
				digits += 1
		url = "https://api.pi.delivery/v1/pi"
		params = {"start": start, "numberOfDigits": digits}
		async with ctx.bot.aiohttp_session.get(url, params = params) as resp:
			data = await resp.json()
		if "content" in data:
			return await ctx.embed_reply(data["content"])
		await ctx.embed_reply(f":no_entry: Error: {data.get('Error', 'N/A')}")
	
	@commands.command(aliases = ["squareroot", "square_root"])
	async def sqrt(self, ctx, value: float):
		'''Square root'''
		await ctx.embed_reply(math.sqrt(value))
	
	# Calculus
	
	@commands.command(aliases = ["differ", "derivative", "differentiation"])
	async def differentiate(self, ctx, *, equation : str):
		'''
		Differentiate an equation<commit_msg>[Discord] Improve type hint formatting for differentiate command<commit_after>
import discord
from discord.ext import commands

import asyncio
import concurrent.futures
import math
import multiprocessing

import sympy

from utilities import checks

def setup(bot):
	bot.add_cog(Math())

class Math(commands.Cog):
	
	'''
	Also see Matrix category
	'''
	
	async def cog_check(self, ctx):
		return await checks.not_forbidden().predicate(ctx)
	
	# Basic
	
	@commands.command()
	async def add(self, ctx, *numbers: float):
		'''Add numbers together'''
		if not numbers:
			await ctx.embed_reply("Add what?")
			return
		await ctx.embed_reply(f"{' + '.join(f'{number:g}' for number in numbers)} = {sum(numbers):g}")
	
	# TODO: Fix/Improve
	@commands.command(aliases = ["calc", "calculator"])
	async def calculate(self, ctx, *, equation: str):
		'''Calculator'''
		#_equation = re.sub("[^[0-9]+-/*^%\.]", "", equation).replace('^', "**") #words
		replacements = {"pi" : "math.pi", 'e' : "math.e", "sin" : "math.sin", 
                        "cos" : "math.cos", "tan" : "math.tan", '^' : "**"}
		allowed = set("0123456789.+-*/^%()")
		for key, value in replacements.items():
			equation = equation.replace(key, value)
		# TODO: use filter
		equation = "".join(character for character in equation if character in allowed)
		print("Calculated " + equation)
		with multiprocessing.Pool(1) as pool:
			async_result = pool.apply_async(eval, (equation,))
			future = ctx.bot.loop.run_in_executor(None, async_result.get, 10.0)
			try:
				result = await asyncio.wait_for(future, 10.0)
				await ctx.embed_reply(f"{equation} = {result}")
			except discord.HTTPException:
				# TODO: use textwrap/paginate
				await ctx.embed_reply(":no_entry: Output too long")
			except SyntaxError:
				await ctx.embed_reply(":no_entry: Syntax error")
			except TypeError as e:
				await ctx.embed_reply(f":no_entry: Error: {e}")
			except ZeroDivisionError:
				await ctx.embed_reply(":no_entry: Error: Division by zero")
			except (concurrent.futures.TimeoutError, multiprocessing.context.TimeoutError):
				await ctx.embed_reply(":no_entry: Execution exceeded time limit")
	
	@commands.command()
	async def exp(self, ctx, value: float):
		'''
		Exponential function
		e ** value | e ^ value
		'''
		try:
			await ctx.embed_reply(math.exp(value))
		except OverflowError as e:
			await ctx.embed_reply(f":no_entry: Error: {e}")
	
	@commands.command()
	async def factorial(self, ctx, value: int):
		'''Factorial'''
		try:
			await ctx.embed_reply(math.factorial(value))
		except OverflowError as e:
			await ctx.embed_reply(f":no_entry: Error: {e}")
	
	@commands.command(aliases = ["greatest_common_divisor"])
	async def gcd(self, ctx, value_a: int, value_b: int):
		'''Greatest common divisor'''
		await ctx.embed_reply(math.gcd(value_a, value_b))
	
	@commands.command(aliases = ['π'])
	async def pi(self, ctx, digits: int = 3, start: int = 1):
		'''Digits of pi'''
		# Handle decimal point being considered digit
		if start <= 1:
			start = 0
			# Don't exceed 1000 digit limit
			if 1 < digits < 1000:
				digits += 1
		url = "https://api.pi.delivery/v1/pi"
		params = {"start": start, "numberOfDigits": digits}
		async with ctx.bot.aiohttp_session.get(url, params = params) as resp:
			data = await resp.json()
		if "content" in data:
			return await ctx.embed_reply(data["content"])
		await ctx.embed_reply(f":no_entry: Error: {data.get('Error', 'N/A')}")
	
	@commands.command(aliases = ["squareroot", "square_root"])
	async def sqrt(self, ctx, value: float):
		'''Square root'''
		await ctx.embed_reply(math.sqrt(value))
	
	# Calculus
	
	@commands.command(aliases = ["differ", "derivative", "differentiation"])
	async def differentiate(self, ctx, *, equation: str):
		'''
		Differentiate an equation
{'fraction_non_alphanumeric': 0.15550813550280074, 'fraction_numerical': 0.009069085089357162, 'mean_word_length': 4.2550805886475125, 'pattern_counts': {'":': 20, '<': 9, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '71871', 'n_tokens_mistral': 2874, 'n_tokens_neox': 2537, 'n_words': 660}