Archived
1
0
Fork 0
This repository has been archived on 2024-04-26. You can view files and clone it, but cannot push or open issues or pull requests.
akari-bot/modules/calc/__init__.py

101 lines
4.3 KiB
Python
Raw Normal View History

2023-01-19 11:27:31 +00:00
from .constant import consts
from core.exceptions import NoReportException
2023-01-17 02:59:22 +00:00
from core.builtins.message import MessageSession
from core.component import on_command
from simpleeval import InvalidExpression, SimpleEval, DEFAULT_FUNCTIONS, DEFAULT_NAMES, DEFAULT_OPERATORS
import ast
import operator as op
import asyncio
import math
2023-01-19 11:52:05 +00:00
import statistics
from typing import Callable, Any
2023-01-19 11:27:31 +00:00
def func_wrapper(func: Callable[..., Any], *args, **kwargs):
for arg in args:
2023-01-19 13:46:06 +00:00
if isinstance(arg, (int, float)) and arg > 100000:
2023-01-19 11:27:31 +00:00
raise NoReportException('参数过大,无法计算。')
return func(*args)
2023-01-17 02:59:22 +00:00
funcs = {}
2023-01-19 11:52:05 +00:00
def add_func(module):
for name in dir(module):
item = getattr(module, name)
if not name.startswith('_') and callable(item):
funcs[name] = lambda *args, item = item, **kwargs: func_wrapper(
item, *args, **kwargs)
add_func(math)
add_func(statistics)
s_eval = SimpleEval(
operators={
**DEFAULT_OPERATORS,
2023-01-19 13:46:06 +00:00
ast.Pow: lambda *args, item=op, **kwargs: func_wrapper(
item, *args, **kwargs),
ast.BitOr: op.or_,
ast.BitAnd: op.and_,
ast.BitXor: op.xor,
ast.Invert: op.invert,
},
2023-01-19 11:27:31 +00:00
functions={**funcs, **DEFAULT_FUNCTIONS},
names={
**DEFAULT_NAMES, **consts,
'pi': math.pi,
'e': math.e,
'tau': math.tau,
'inf': math.inf, 'nan': math.nan,
},)
2023-01-19 07:28:01 +00:00
2023-01-17 02:59:22 +00:00
c = on_command('calc', developers=[
2023-01-19 13:46:06 +00:00
'Dianliang233'], desc='安全地计算 Python ast 表达式。', required_superuser=True)
2023-01-17 02:59:22 +00:00
@c.handle('<math_expression>', options_desc={'+': '和/正数1 + 2 -> 3',
'-': '差/负数3 - 1 -> 2',
2023-01-17 02:59:22 +00:00
'/': '6 / 3 -> 2',
'//': '整除7 // 4 -> 1',
2023-01-17 02:59:22 +00:00
'*': '2 * 3 -> 6',
'**': 'x 的 y 次幂(由于性能问题,结果不得超过 4e+62 ** 3 -> 8',
'%': '取模5 % 2 -> 1',
'==': '等于1 == 1 -> True',
'<': '小于1 < 2 -> True',
'>': '大于2 > 1 -> True',
'<=': '小于等于1 <= 2 -> True',
'>>': 'x 右移 y 位(相当于 x / (2 ** y)y < 1000032 >> 5 -> 1',
'<<': 'x 左移 y 位(相当于 x * (2 ** y)y < 100001 << 5 -> 32',
'in': 'x 在 y 中:"hat" in "what" -> True',
'not': 'not True -> False',
'is': 'x 与 y 是同一个对象1 is 1 -> True',
2023-01-17 02:59:22 +00:00
'randint(x)': '小于 x 的随机整数randint(6) -> 5',
'rand()': '0 与 1 之间的随机浮点数rand() -> 0.5789015836448923',
'int()': '转换为整数int(1.5) -> 1',
'float()': '转换为浮点数float(1) -> 1.0',
'str()': '转换为字符串str(1) -> "1"',
2023-01-19 11:52:05 +00:00
'更多数学函数': 'https://docs.python.org/zh-cn/3/library/math.html',
'更多统计函数': 'https://docs.python.org/zh-cn/3/library/statistics.html',
2023-01-17 02:59:22 +00:00
})
async def _(msg: MessageSession):
try:
res = await asyncio.wait_for(async_eval(msg.parsed_msg["<math_expression>"]), 15)
await msg.finish(f'{(msg.parsed_msg["<math_expression>"])} = {str(res)}')
2023-01-17 02:59:22 +00:00
except InvalidExpression as e:
await msg.finish(f"表达式无效:{e}")
except asyncio.TimeoutError:
raise TimeoutException()
2023-01-19 07:28:01 +00:00
except Exception as e:
raise NoReportException(e)
async def async_eval(expr: str):
return s_eval.eval(expr)
class TimeoutException(NoReportException):
'''计算超时,最大计算时间为 15 秒。'''
pass