소스 검색

More annotations

master
Rocketsoup 4 년 전
부모
커밋
2eb8b1fcdc
3개의 변경된 파일82개의 추가작업 그리고 53개의 파일을 삭제
  1. 55
    29
      rocketbot/botmessage.py
  2. 25
    22
      rocketbot/cogsetting.py
  3. 2
    2
      rocketbot/utils.py

+ 55
- 29
rocketbot/botmessage.py 파일 보기

2
 Classes for crafting messages from the bot. Content can change as information
2
 Classes for crafting messages from the bot. Content can change as information
3
 changes, and mods can perform actions on the message via emoji reactions.
3
 changes, and mods can perform actions on the message via emoji reactions.
4
 """
4
 """
5
+from typing import Any, Optional, Union
6
+
5
 from datetime import datetime
7
 from datetime import datetime
6
 from discord import Guild, Message, PartialEmoji, TextChannel
8
 from discord import Guild, Message, PartialEmoji, TextChannel
7
 
9
 
20
 	to explain why an action is no longer available.
22
 	to explain why an action is no longer available.
21
 	"""
23
 	"""
22
 	def __init__(self, emoji: str, is_enabled: bool, description: str):
24
 	def __init__(self, emoji: str, is_enabled: bool, description: str):
23
-		self.emoji = emoji
24
-		self.is_enabled = is_enabled
25
-		self.description = description
25
+		"""
26
+		Creates a bot message reaction.
27
+		- emoji: The emoji string
28
+		- is_enabled: Whether the emoji can be used
29
+		- description: What reacting with this emoji does (or an explanation of
30
+		  why it's disabled)
31
+		"""
32
+		self.emoji: str = emoji
33
+		self.is_enabled: bool = is_enabled
34
+		self.description: str = description
26
 
35
 
27
 	def __eq__(self, other):
36
 	def __eq__(self, other):
28
 		return other is not None and \
37
 		return other is not None and \
36
 			message_count: int = 1,
45
 			message_count: int = 1,
37
 			did_kick: bool = None,
46
 			did_kick: bool = None,
38
 			did_ban: bool = None,
47
 			did_ban: bool = None,
39
-			user_count: int = 1) -> list:
48
+			user_count: int = 1) -> list[BotMessageReaction]:
40
 		"""
49
 		"""
41
 		Convenience factory for generating any of the three most common
50
 		Convenience factory for generating any of the three most common
42
 		commands: delete message(s), kick user(s), and ban user(s). All
51
 		commands: delete message(s), kick user(s), and ban user(s). All
55
 		- user_count     How many users there are. Used for pluralizing
64
 		- user_count     How many users there are. Used for pluralizing
56
 		                 description. Defaults to 1. Omit if n/a.
65
 		                 description. Defaults to 1. Omit if n/a.
57
 		"""
66
 		"""
58
-		reactions = []
67
+		reactions: list[BotMessageReaction] = []
59
 		if did_delete is not None:
68
 		if did_delete is not None:
60
 			if did_delete:
69
 			if did_delete:
61
 				reactions.append(BotMessageReaction(
70
 				reactions.append(BotMessageReaction(
104
 	actions that can be taken via a mod reacting to the message.
113
 	actions that can be taken via a mod reacting to the message.
105
 	"""
114
 	"""
106
 
115
 
107
-	TYPE_DEFAULT = 0
108
-	TYPE_INFO = 1
109
-	TYPE_MOD_WARNING = 2
110
-	TYPE_SUCCESS = 3
111
-	TYPE_FAILURE = 4
116
+	TYPE_DEFAULT: int = 0
117
+	TYPE_INFO: int = 1
118
+	TYPE_MOD_WARNING: int = 2
119
+	TYPE_SUCCESS: int = 3
120
+	TYPE_FAILURE: int = 4
112
 
121
 
113
 	def __init__(self,
122
 	def __init__(self,
114
 			guild: Guild,
123
 			guild: Guild,
115
 			text: str,
124
 			text: str,
116
 			type: int = TYPE_DEFAULT, # pylint: disable=redefined-builtin
125
 			type: int = TYPE_DEFAULT, # pylint: disable=redefined-builtin
117
-			context = None,
118
-			reply_to: Message = None):
119
-		self.guild = guild
120
-		self.text = text
121
-		self.type = type
122
-		self.context = context
123
-		self.quote = None
126
+			context: Optional[Any] = None,
127
+			reply_to: Optional[Message] = None):
128
+		"""
129
+		Creates a bot message.
130
+		- guild: The Discord guild to send the message to.
131
+		- text: Main text of the message.
132
+		- type: One of the TYPE_ constants.
133
+		- context: Arbitrary value that will be passed in the callback. Can be
134
+		  associated data for performing some action. (optional)
135
+		- reply_to: Existing message this message is in reply to. (optional)
136
+		"""
137
+		self.guild: Guild = guild
138
+		self.text: str = text
139
+		self.type: int = type
140
+		self.context: Optional[Any] = context
141
+		self.quote: Optional[str] = None
124
 		self.source_cog = None  # Set by `BaseCog.post_message()`
142
 		self.source_cog = None  # Set by `BaseCog.post_message()`
125
-		self.__posted_text = None  # last text posted, to test for changes
126
-		self.__posted_emoji = set()
127
-		self.__message = None  # Message
128
-		self.__reply_to = reply_to
129
-		self.__reactions = []  # BotMessageReaction[]
143
+		self.__posted_text: str = None  # last text posted, to test for changes
144
+		self.__posted_emoji: set[str] = set()  # last emoji list posted
145
+		self.__message: Optional[Message] = None  # set once the message has been posted
146
+		self.__reply_to: Optional[Message] = reply_to
147
+		self.__reactions: list[BotMessageReaction] = []
130
 
148
 
131
 	def is_sent(self) -> bool:
149
 	def is_sent(self) -> bool:
132
 		"""
150
 		"""
136
 		"""
154
 		"""
137
 		return self.__message is not None
155
 		return self.__message is not None
138
 
156
 
139
-	def message_id(self):
157
+	def message_id(self) -> Optional[int]:
140
 		'Returns the Message id or None if not sent.'
158
 		'Returns the Message id or None if not sent.'
141
 		return self.__message.id if self.__message else None
159
 		return self.__message.id if self.__message else None
142
 
160
 
143
-	def message_sent_at(self) -> datetime:
161
+	def message_sent_at(self) -> Optional[datetime]:
144
 		'Returns when the message was sent or None if not sent.'
162
 		'Returns when the message was sent or None if not sent.'
145
 		return self.__message.created_at if self.__message else None
163
 		return self.__message.created_at if self.__message else None
146
 
164
 
156
 		self.text = new_text
174
 		self.text = new_text
157
 		await self.update_if_sent()
175
 		await self.update_if_sent()
158
 
176
 
159
-	async def set_reactions(self, reactions: list) -> None:
177
+	async def set_reactions(self, reactions: list[BotMessageReaction]) -> None:
160
 		"""
178
 		"""
161
 		Replaces all BotMessageReactions with a new list. If the message has
179
 		Replaces all BotMessageReactions with a new list. If the message has
162
 		been sent, it will be updated.
180
 		been sent, it will be updated.
194
 			self.__reactions.append(reaction)
212
 			self.__reactions.append(reaction)
195
 		await self.update_if_sent()
213
 		await self.update_if_sent()
196
 
214
 
197
-	async def remove_reaction(self, reaction_or_emoji) -> None:
215
+	async def remove_reaction(self, reaction_or_emoji: Union[BotMessageReaction, str]) -> None:
198
 		"""
216
 		"""
199
 		Removes a reaction. Can pass either a BotMessageReaction or just the
217
 		Removes a reaction. Can pass either a BotMessageReaction or just the
200
 		emoji string. If the message has been sent, it will be updated.
218
 		emoji string. If the message has been sent, it will be updated.
207
 				await self.update_if_sent()
225
 				await self.update_if_sent()
208
 				return
226
 				return
209
 
227
 
210
-	def reaction_for_emoji(self, emoji) -> BotMessageReaction:
228
+	def reaction_for_emoji(self, emoji) -> Optional[BotMessageReaction]:
211
 		"""
229
 		"""
212
 		Finds the BotMessageReaction for the given emoji or None if not found.
230
 		Finds the BotMessageReaction for the given emoji or None if not found.
213
 		Accepts either a PartialEmoji or str.
231
 		Accepts either a PartialEmoji or str.
245
 			else:
263
 			else:
246
 				channel_id = Storage.get_config_value(self.guild, ConfigKey.WARNING_CHANNEL_ID)
264
 				channel_id = Storage.get_config_value(self.guild, ConfigKey.WARNING_CHANNEL_ID)
247
 				if channel_id is None:
265
 				if channel_id is None:
248
-					bot_log(self.guild, None, '\u0007No warning channel set! No warning issued.')
266
+					bot_log(self.guild, \
267
+						type(self.source_cog) if self.source_cog else None, \
268
+						'\u0007No warning channel set! No warning issued.')
249
 					return
269
 					return
250
 				channel: TextChannel = self.guild.get_channel(channel_id)
270
 				channel: TextChannel = self.guild.get_channel(channel_id)
251
 				if channel is None:
271
 				if channel is None:
252
-					bot_log(self.guild, None, '\u0007Configured warning channel does not exist!')
272
+					bot_log(self.guild, \
273
+						type(self.source_cog) if self.source_cog else None, \
274
+						'\u0007Configured warning channel does not exist!')
253
 					return
275
 					return
254
 				self.__message = await channel.send(content=content)
276
 				self.__message = await channel.send(content=content)
255
 				self.__posted_text = content
277
 				self.__posted_text = content
267
 				self.__posted_emoji.remove(emoji)
289
 				self.__posted_emoji.remove(emoji)
268
 
290
 
269
 	def __formatted_message(self) -> str:
291
 	def __formatted_message(self) -> str:
292
+		"""
293
+		Composes the entire message markdown from components. Includes the main
294
+		message, quoted text, summary of available reactions, etc.
295
+		"""
270
 		s: str = ''
296
 		s: str = ''
271
 
297
 
272
 		if self.type == self.TYPE_INFO:
298
 		if self.type == self.TYPE_INFO:

+ 25
- 22
rocketbot/cogsetting.py 파일 보기

1
 """
1
 """
2
 A guild configuration setting available for editing via bot commands.
2
 A guild configuration setting available for editing via bot commands.
3
 """
3
 """
4
+from types import coroutine
5
+from typing import Any, Optional, Type
6
+
4
 from discord.ext import commands
7
 from discord.ext import commands
5
 from discord.ext.commands import Bot, Cog, Command, Context, Group
8
 from discord.ext.commands import Bot, Cog, Command, Context, Group
6
 
9
 
11
 class CogSetting:
14
 class CogSetting:
12
 	"""
15
 	"""
13
 	Describes a configuration setting for a guild that can be edited by the
16
 	Describes a configuration setting for a guild that can be edited by the
14
-	mods of those guilds. BaseCog can generate "get" and "set" commands
15
-	automatically, reducing the boilerplate of generating commands manually.
16
-	Offers simple validation rules.
17
+	mods of those guilds. BaseCog can generate "get" and "set" commands (or
18
+	"enable" and "disable" commands for boolean values) automatically, reducing
19
+	the boilerplate of generating commands manually. Offers simple validation rules.
17
 	"""
20
 	"""
18
 	def __init__(self,
21
 	def __init__(self,
19
 			name: str,
22
 			name: str,
20
-			datatype,
21
-			brief: str = None,
22
-			description: str = None,
23
-			usage: str = None,
24
-			min_value = None,
25
-			max_value = None,
26
-			enum_values: set = None):
23
+			datatype: Type,
24
+			brief: Optional[str] = None,
25
+			description: Optional[str] = None,
26
+			usage: Optional[str] = None,
27
+			min_value: Optional[Any] = None,
28
+			max_value: Optional[Any] = None,
29
+			enum_values: Optional[set[Any]] = None):
27
 		"""
30
 		"""
28
 		Params:
31
 		Params:
29
 		- name         Setting identifier. Must follow variable naming
32
 		- name         Setting identifier. Must follow variable naming
41
 		- max_value    Largest allowable value. None for no maximum.
44
 		- max_value    Largest allowable value. None for no maximum.
42
 		- enum_values  Set of allowed values. None if unconstrained.
45
 		- enum_values  Set of allowed values. None if unconstrained.
43
 		"""
46
 		"""
44
-		self.name = name
45
-		self.datatype = datatype
46
-		self.brief = brief
47
-		self.description = description or ''  # Can't be None
48
-		self.usage = usage
49
-		self.min_value = min_value
50
-		self.max_value = max_value
51
-		self.enum_values = enum_values
47
+		self.name: str = name
48
+		self.datatype: Type = datatype
49
+		self.brief: Optional[str] = brief
50
+		self.description: str = description or ''  # Can't be None
51
+		self.usage: Optional[str] = usage
52
+		self.min_value: Optional[Any] = min_value
53
+		self.max_value: Optional[Any] = max_value
54
+		self.enum_values: Optional[set[Any]] = enum_values
52
 		if self.enum_values or self.min_value is not None or self.max_value is not None:
55
 		if self.enum_values or self.min_value is not None or self.max_value is not None:
53
 			self.description += '\n'
56
 			self.description += '\n'
54
 		if self.enum_values:
57
 		if self.enum_values:
86
 			(group or bot).add_command(self.__make_setter_command(cog))
89
 			(group or bot).add_command(self.__make_setter_command(cog))
87
 
90
 
88
 	def __make_getter_command(self, cog: Cog) -> Command:
91
 	def __make_getter_command(self, cog: Cog) -> Command:
89
-		setting = self
92
+		setting: CogSetting = self
90
 		async def getter(cog: Cog, context: Context) -> None:
93
 		async def getter(cog: Cog, context: Context) -> None:
91
 			setting_name = setting.name
94
 			setting_name = setting.name
92
 			if context.command.parent:
95
 			if context.command.parent:
144
 		async def setter_bool(cog, context, new_value: bool):
147
 		async def setter_bool(cog, context, new_value: bool):
145
 			await setter_common(cog, context, new_value)
148
 			await setter_common(cog, context, new_value)
146
 
149
 
147
-		setter = None
150
+		setter: coroutine = None
148
 		if setting.datatype == int:
151
 		if setting.datatype == int:
149
 			setter = setter_int
152
 			setter = setter_int
150
 		elif setting.datatype == float:
153
 		elif setting.datatype == float:
167
 				commands.guild_only(),
170
 				commands.guild_only(),
168
 			])
171
 			])
169
 		# Passing `cog` in init gets ignored and set to `None` so set after.
172
 		# Passing `cog` in init gets ignored and set to `None` so set after.
170
-		# This ensures the callback is passed `self`.
173
+		# This ensures the callback is passed the cog as `self` argument.
171
 		command.cog = cog
174
 		command.cog = cog
172
 		return command
175
 		return command
173
 
176
 
218
 		return command
221
 		return command
219
 
222
 
220
 	@classmethod
223
 	@classmethod
221
-	def set_up_all(cls, cog: Cog, bot: Bot, settings: list) -> None:
224
+	def set_up_all(cls, cog: Cog, bot: Bot, settings: list[CogSetting]) -> None:
222
 		"""
225
 		"""
223
 		Sets up editing commands for a list of CogSettings and adds them to a
226
 		Sets up editing commands for a list of CogSettings and adds them to a
224
 		cog. If the cog has a command Group, commands will be added to it.
227
 		cog. If the cog has a command Group, commands will be added to it.

+ 2
- 2
rocketbot/utils.py 파일 보기

3
 """
3
 """
4
 import re
4
 import re
5
 from datetime import datetime, timedelta
5
 from datetime import datetime, timedelta
6
-from typing import Any, Union
6
+from typing import Any, Optional, Type, Union
7
 
7
 
8
 from discord import Guild
8
 from discord import Guild
9
 from discord.ext.commands import Cog, Group
9
 from discord.ext.commands import Cog, Group
86
 			return member
86
 			return member
87
 	return None
87
 	return None
88
 
88
 
89
-def bot_log(guild: Guild, cog_class, message: Any) -> None:
89
+def bot_log(guild: Optional[Guild], cog_class: Optional[Type], message: Any) -> None:
90
 	'Logs a message to stdout with time, cog, and guild info.'
90
 	'Logs a message to stdout with time, cog, and guild info.'
91
 	now: datetime = datetime.now() # local
91
 	now: datetime = datetime.now() # local
92
 	s = f'[{now.strftime("%Y-%m-%dT%H:%M:%S")}|'
92
 	s = f'[{now.strftime("%Y-%m-%dT%H:%M:%S")}|'

Loading…
취소
저장