-
Notifications
You must be signed in to change notification settings - Fork 5
/
Context.py
141 lines (119 loc) · 4.08 KB
/
Context.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from collections import namedtuple
import datetime
import discord
import asyncio # noqa
# from .logger import log
from . import lib
from . import cmdClient # noqa
from .Command import Command # noqa
FlatContext = namedtuple(
'FlatContext',
('msg',
'ch',
'guild',
'arg_str',
'cmd',
'alias',
'author',
'prefix',
'cleanup_on_edit',
'reparse_on_edit',
'sent_messages')
)
class Context(object):
__slots__ = (
'client',
'msg',
'ch',
'guild',
'objects',
'args',
'arg_str',
'cmd',
'alias',
'author',
'prefix',
'sent_messages',
'cleanup_on_edit',
'reparse_on_edit',
'tasks'
)
def __init__(self, client, **kwargs):
self.client = client # type: cmdClient.cmdClient
self.msg = kwargs.pop("message", None) # type: discord.Message
self.ch = self.msg.channel if self.msg is not None else kwargs.pop("channel", None) # type: discord.Channel
self.guild = self.msg.guild if self.msg is not None else kwargs.pop("guild", None) # type: discord.Guild
self.author = self.msg.author if self.msg is not None else kwargs.pop("author", None) # type: discord.User
self.arg_str = kwargs.pop("arg_str", None) # type: str
self.cmd = kwargs.pop("cmd", None) # type: Command
self.alias = kwargs.pop("alias", None) # type: str
self.prefix = kwargs.pop("prefix", None) # type: str
self.cleanup_on_edit = kwargs.pop(
"cleanup_on_edit",
self.cmd.handle_edits if self.cmd is not None else True
)
self.reparse_on_edit = kwargs.pop(
"reparse_on_edit",
self.cmd.handle_edits if self.cmd is not None else True
)
# Argument string, intended to be overriden by argument parsers
self.args = self.arg_str # type:str
# Cache of messages sent in this context.
self.sent_messages = [] # type: List[discord.Message]
# Context tasks, including for the final wrapped command
self.tasks = [] # type: List[asyncio.Task]
@classmethod
def util(cls, util_func):
"""
Decorator to make a utility function available as a Context instance method
"""
setattr(cls, util_func.__name__, util_func)
def flatten(self):
"""
Returns a flat version of the current context for debugging or caching.
Does not store `objects`.
Intended to be overriden if different cache data is needed.
"""
return FlatContext(
msg=self.msg.id if self.msg else None,
ch=self.ch.id if self.ch else None,
guild=self.guild.id if self.guild else None,
arg_str=self.arg_str,
cmd=self.cmd.name if self.cmd else None,
alias=self.alias,
author=self.author.id if self.author else None,
prefix=self.prefix,
cleanup_on_edit=self.cleanup_on_edit,
reparse_on_edit=self.reparse_on_edit,
sent_messages=tuple([message.id for message in self.sent_messages])
)
@Context.util
async def reply(ctx, content=None, allow_everyone=False, **kwargs):
"""
Helper function to reply in the current channel.
"""
if not allow_everyone:
if content:
content = lib.sterilise_content(content)
message = await ctx.ch.send(content=content, **kwargs)
ctx.sent_messages.append(message)
return message
@Context.util
async def error_reply(ctx, error_str):
"""
Notify the user of a user level error.
Typically, this will occur in a red embed, posted in the command channel.
"""
embed = discord.Embed(
colour=discord.Colour.red(),
description=error_str,
timestamp=datetime.datetime.utcnow()
)
try:
message = await ctx.ch.send(embed=embed)
ctx.sent_messages.append(message)
return message
except discord.Forbidden:
message = await ctx.reply(error_str)
ctx.sent_messages.append(message)
return message