or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-commands.mdautomod.mdchannels-messaging.mdclient-bot.mdcommand-framework.mderror-handling.mdevents-gateway.mdguild-management.mdindex.mdinteractions-ui.mdlocalization-i18n.mdpermissions-security.mdpolls.mdusers-members.mdvoice-audio.md

polls.mddocs/

0

# Poll System

1

2

Discord's native poll system allows creating interactive polls with multiple choice answers, emojis, and automatic vote counting. Disnake provides full support for creating, managing, and responding to polls.

3

4

## Capabilities

5

6

### Poll Media

7

8

Represents the content of poll questions and answers, supporting both text and emoji elements.

9

10

```python { .api }

11

class PollMedia:

12

def __init__(

13

self,

14

text: str,

15

emoji: Optional[Union[Emoji, PartialEmoji, str]] = None

16

):

17

"""

18

Create poll media (question or answer content).

19

20

Parameters:

21

- text: Text content for the media

22

- emoji: Optional emoji to display with the text

23

"""

24

25

@property

26

def text(self) -> Optional[str]:

27

"""Text content of the media."""

28

29

@property

30

def emoji(self) -> Optional[Union[Emoji, PartialEmoji]]:

31

"""Emoji associated with the media."""

32

```

33

34

### Poll Answer

35

36

Represents a single answer option in a poll with vote tracking.

37

38

```python { .api }

39

class PollAnswer:

40

def __init__(self, *, data: PollAnswerPayload):

41

"""

42

Poll answer option.

43

44

Parameters:

45

- data: Raw answer data from Discord API

46

"""

47

48

@property

49

def id(self) -> int:

50

"""Answer ID."""

51

52

@property

53

def media(self) -> PollMedia:

54

"""Media content for this answer."""

55

56

@property

57

def vote_count(self) -> int:

58

"""Number of votes this answer has received."""

59

60

@property

61

def me_voted(self) -> bool:

62

"""Whether the current user voted for this answer."""

63

64

def get_voters(self, *, limit: Optional[int] = None, after: Optional[Snowflake] = None) -> PollAnswerIterator:

65

"""

66

Get users who voted for this answer.

67

68

Parameters:

69

- limit: Maximum number of voters to retrieve

70

- after: Get voters after this user ID

71

72

Returns:

73

Iterator for poll answer voters

74

"""

75

```

76

77

### Poll

78

79

Complete poll object with question, answers, and configuration.

80

81

```python { .api }

82

class Poll:

83

def __init__(self, *, data: PollPayload, state: ConnectionState):

84

"""

85

Discord poll instance.

86

87

Parameters:

88

- data: Raw poll data from Discord API

89

- state: Connection state for API calls

90

"""

91

92

@property

93

def question(self) -> PollMedia:

94

"""Poll question content."""

95

96

@property

97

def answers(self) -> List[PollAnswer]:

98

"""All answer options for the poll."""

99

100

@property

101

def expiry(self) -> Optional[datetime]:

102

"""When the poll expires and stops accepting votes."""

103

104

@property

105

def allow_multiselect(self) -> bool:

106

"""Whether users can select multiple answers."""

107

108

@property

109

def layout_type(self) -> PollLayoutType:

110

"""Layout type for displaying the poll."""

111

112

@property

113

def total_vote_count(self) -> int:

114

"""Total number of votes across all answers."""

115

116

@property

117

def is_finalized(self) -> bool:

118

"""Whether the poll has been finalized (expired or manually ended)."""

119

120

def get_answer(self, answer_id: int) -> Optional[PollAnswer]:

121

"""

122

Get a specific answer by ID.

123

124

Parameters:

125

- answer_id: Answer ID to look up

126

127

Returns:

128

PollAnswer if found, None otherwise

129

"""

130

131

async def end(self) -> Message:

132

"""

133

End the poll immediately.

134

135

Returns:

136

Updated message with finalized poll

137

"""

138

139

@classmethod

140

def create(

141

cls,

142

question: Union[str, PollMedia],

143

*answers: Union[str, PollMedia],

144

duration: Optional[Union[int, timedelta]] = None,

145

allow_multiselect: bool = False,

146

) -> PollCreatePayload:

147

"""

148

Create poll data for sending in a message.

149

150

Parameters:

151

- question: Poll question text or media

152

- answers: Answer options (2-10 answers required)

153

- duration: Poll duration in hours (1-168) or timedelta

154

- allow_multiselect: Whether to allow multiple answer selection

155

156

Returns:

157

Poll creation payload for message sending

158

"""

159

```

160

161

## Usage Examples

162

163

### Creating Basic Polls

164

165

```python

166

import disnake

167

from disnake import Poll, PollMedia

168

169

@bot.slash_command(description="Create a simple poll")

170

async def poll(

171

inter: disnake.ApplicationCommandInteraction,

172

question: str = disnake.Param(description="Poll question"),

173

option1: str = disnake.Param(description="First option"),

174

option2: str = disnake.Param(description="Second option"),

175

option3: str = disnake.Param(description="Third option", default=None),

176

option4: str = disnake.Param(description="Fourth option", default=None),

177

duration: int = disnake.Param(description="Duration in hours (1-168)", default=24)

178

):

179

# Collect non-empty options

180

options = [option1, option2]

181

if option3:

182

options.append(option3)

183

if option4:

184

options.append(option4)

185

186

# Create poll

187

poll_data = Poll.create(

188

question=question,

189

*options,

190

duration=duration,

191

allow_multiselect=False

192

)

193

194

await inter.response.send_message(poll=poll_data)

195

196

@bot.slash_command(description="Create a poll with emojis")

197

async def emoji_poll(inter: disnake.ApplicationCommandInteraction):

198

poll_data = Poll.create(

199

question=PollMedia("What's your favorite fruit?", "🍎"),

200

PollMedia("Apple", "🍎"),

201

PollMedia("Banana", "🍌"),

202

PollMedia("Orange", "🍊"),

203

PollMedia("Grapes", "πŸ‡"),

204

duration=48,

205

allow_multiselect=True

206

)

207

208

await inter.response.send_message(

209

"Vote for your favorite fruits! (You can pick multiple)",

210

poll=poll_data

211

)

212

```

213

214

### Advanced Poll Features

215

216

```python

217

from datetime import timedelta

218

219

@bot.slash_command(description="Create a multi-select poll")

220

async def multiselect_poll(inter: disnake.ApplicationCommandInteraction):

221

poll_data = Poll.create(

222

question="Which programming languages do you know?",

223

"Python",

224

"JavaScript",

225

"Java",

226

"C++",

227

"Go",

228

"Rust",

229

duration=timedelta(days=3),

230

allow_multiselect=True

231

)

232

233

await inter.response.send_message(

234

"Select all languages you're familiar with:",

235

poll=poll_data

236

)

237

238

@bot.slash_command(description="Create a timed poll")

239

async def quick_poll(inter: disnake.ApplicationCommandInteraction):

240

poll_data = Poll.create(

241

question="Should we start the meeting now?",

242

"Yes, let's start",

243

"Wait 5 more minutes",

244

"Postpone to later",

245

duration=1 # 1 hour only

246

)

247

248

await inter.response.send_message(

249

"Quick decision needed:",

250

poll=poll_data

251

)

252

```

253

254

### Monitoring Poll Results

255

256

```python

257

@bot.event

258

async def on_message(message):

259

# Check if message has a poll

260

if message.poll:

261

print(f"Poll found: {message.poll.question.text}")

262

print(f"Total votes: {message.poll.total_vote_count}")

263

264

for answer in message.poll.answers:

265

print(f" {answer.media.text}: {answer.vote_count} votes")

266

267

@bot.slash_command(description="Get poll results")

268

async def poll_results(

269

inter: disnake.ApplicationCommandInteraction,

270

message_id: str = disnake.Param(description="Message ID containing the poll")

271

):

272

try:

273

message = await inter.channel.fetch_message(int(message_id))

274

275

if not message.poll:

276

await inter.response.send_message("That message doesn't contain a poll.", ephemeral=True)

277

return

278

279

poll = message.poll

280

embed = disnake.Embed(

281

title="Poll Results",

282

description=f"**{poll.question.text}**",

283

color=disnake.Color.blue()

284

)

285

286

if poll.is_finalized:

287

embed.add_field(name="Status", value="βœ… Finalized", inline=True)

288

elif poll.expiry:

289

embed.add_field(name="Expires", value=f"<t:{int(poll.expiry.timestamp())}:R>", inline=True)

290

291

embed.add_field(name="Total Votes", value=str(poll.total_vote_count), inline=True)

292

293

# Add results for each answer

294

for i, answer in enumerate(poll.answers, 1):

295

percentage = (answer.vote_count / poll.total_vote_count * 100) if poll.total_vote_count > 0 else 0

296

297

value = f"{answer.vote_count} votes ({percentage:.1f}%)"

298

if answer.media.emoji:

299

name = f"{answer.media.emoji} {answer.media.text}"

300

else:

301

name = f"{i}. {answer.media.text}"

302

303

embed.add_field(name=name, value=value, inline=False)

304

305

await inter.response.send_message(embed=embed)

306

307

except (ValueError, disnake.NotFound):

308

await inter.response.send_message("Message not found.", ephemeral=True)

309

310

@bot.slash_command(description="End a poll early")

311

async def end_poll(

312

inter: disnake.ApplicationCommandInteraction,

313

message_id: str = disnake.Param(description="Message ID containing the poll")

314

):

315

try:

316

message = await inter.channel.fetch_message(int(message_id))

317

318

if not message.poll:

319

await inter.response.send_message("That message doesn't contain a poll.", ephemeral=True)

320

return

321

322

if message.poll.is_finalized:

323

await inter.response.send_message("That poll is already finalized.", ephemeral=True)

324

return

325

326

# End the poll

327

updated_message = await message.poll.end()

328

await inter.response.send_message(f"Poll ended! Final results posted in {message.jump_url}")

329

330

except (ValueError, disnake.NotFound):

331

await inter.response.send_message("Message not found.", ephemeral=True)

332

except disnake.Forbidden:

333

await inter.response.send_message("I don't have permission to end that poll.", ephemeral=True)

334

```

335

336

### Getting Poll Voters

337

338

```python

339

@bot.slash_command(description="See who voted for a specific answer")

340

async def poll_voters(

341

inter: disnake.ApplicationCommandInteraction,

342

message_id: str = disnake.Param(description="Message ID containing the poll"),

343

answer_number: int = disnake.Param(description="Answer number (1, 2, 3, etc.)")

344

):

345

try:

346

message = await inter.channel.fetch_message(int(message_id))

347

348

if not message.poll:

349

await inter.response.send_message("That message doesn't contain a poll.", ephemeral=True)

350

return

351

352

poll = message.poll

353

if answer_number < 1 or answer_number > len(poll.answers):

354

await inter.response.send_message(f"Invalid answer number. Must be 1-{len(poll.answers)}.", ephemeral=True)

355

return

356

357

answer = poll.answers[answer_number - 1]

358

voters = []

359

360

# Get up to 25 voters for this answer

361

async for user in answer.get_voters(limit=25):

362

voters.append(user.display_name)

363

364

if not voters:

365

await inter.response.send_message(f"No votes yet for: {answer.media.text}", ephemeral=True)

366

return

367

368

embed = disnake.Embed(

369

title="Poll Voters",

370

description=f"**Answer:** {answer.media.text}\n**Votes:** {answer.vote_count}",

371

color=disnake.Color.green()

372

)

373

374

voters_text = "\n".join(voters)

375

if len(voters) == 25:

376

voters_text += "\n... and more"

377

378

embed.add_field(name="Voters", value=voters_text, inline=False)

379

380

await inter.response.send_message(embed=embed)

381

382

except (ValueError, disnake.NotFound):

383

await inter.response.send_message("Message not found.", ephemeral=True)

384

```