Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

channel.position often reflects creation order instead of sort order #2392

Open
3 tasks done
EclipsedSolari opened this issue Oct 24, 2019 · 7 comments
Open
3 tasks done
Labels
docs needed Documentation is needed for this change. help appreciated Good issue to work on

Comments

@EclipsedSolari
Copy link

Summary

This one's so bizarre it might actually be a Discord bug.

New channels often have channel.position set according to creation order rather than sort order. Restarting the bot does not change channel position order. Manually dragging any channel in the Discord client resets all channels' positions to correctly indicate sort order.

Reproduction Steps

import discord
import random

client = discord.Client()
new_index = 1

@client.event
async def on_message(message):
    global new_index

    if message.author == client.user:
        return

    if message.content.startswith('/create'):
        channel_name = f"test{new_index}"
        new_index = new_index + 1

        # create a new channel at a random position in the server
        server = message.channel.guild
        position = random.randint(0, len(server.channels))
        new_channel = await server.create_text_channel(name=channel_name, position=position)
        await new_channel.send(f"I have position {new_channel.position}!")

    if message.content.startswith('/position'):
        for channel in message.channel_mentions:
            await message.channel.send(f"Channel {channel.name} has position {channel.position}.")

client.run('token')

Use /create to create a channel at a random position within the server and immediately report its position. I'm getting results like "I have position 23!" for a channel with visual position 10.

Use /position to check the position of a manually created channel. As long as the channel is freshly created, it demonstrates the issue just as well as a bot-created channel.

Without changing any channels, restart the bot and query /position again. Channel positions don't change.

Manually reorder any channel in the server and query /position again. All channel positions magically snap into sort order.

Expected Results

I expect channel.position to indicate the channel's sort position, as stated in both discord.py's documentation and discord's own documentation.

Actual Results

channel.position for newly created channels reflects creation order rather than sort order.

image

Checklist

  • I have searched the open issues for duplicates.
  • I have shown the entire traceback, if possible.
  • I have removed my token from display, if visible.

System Information

  • Python v3.7.5-final
  • discord.py v1.2.4-final
  • aiohttp v3.5.4
  • websockets v6.0
  • system info: Windows 10 10.0.18362
@khazhyk
Copy link
Collaborator

khazhyk commented Oct 24, 2019

Are the channels still in order relative to each other?

@EclipsedSolari
Copy link
Author

It looks like the channels do keep relative order, yes. In the demo script above, if /create creates two channels, and the second is created visually above the first, like this:

#test2
#test1

then #test2 gets a lower channel.position than #test1 despite being created after it. However, both channel.position values remain incorrect based on where the channels are actually sorted.

@khazhyk
Copy link
Collaborator

khazhyk commented Oct 24, 2019

This is WAI, discord probably isn't going to change it any time soon. channel.position is used for sorting order only, and shouldn't be relied on to determine the "nth" channel - it's possible e.g. for multiple channels in the server to have the same position, e.g., etc.

Might be a handy feature to have a order property? but you'd likely need to order the channels anyways to figure that out, since it's stored as a dict, so just sort the channels and enumerate?

@EclipsedSolari
Copy link
Author

Okay, so to accomplish sorting the channels (my original goal), I need to stop looking at channel.position as an absolute value and start looking at it as a relative value? E.g. if channel1.position < channel2.position and channel1.category_id == channel2.category_id, channel1 will visually sort above channel2?

I don't believe this is intuitive, so a note in the documentation might be helpful, but I think it still allows a form of channel sorting as long as I'm careful about it. Thank you for the clarification!

@Rapptz Rapptz added the question This is a question about the library label Oct 24, 2019
@Rapptz
Copy link
Owner

Rapptz commented Oct 24, 2019

I guess an __lt__ and friends for GuildChannel might make sense. You can get the sorted GUI order of channels using Guild.text_channels, Guild.voice_channels, or Guild.by_category.

@Rapptz Rapptz removed the question This is a question about the library label Sep 18, 2020
@egnor
Copy link

egnor commented Oct 13, 2020

The documentation should be fixed, I think. For example, the reference for TextChannel says "position - The position in the channel list. This is a number that starts at 0. e.g. the top channel is position 0". That makes it sound like an index into the list, which it most definitely is not. (And that's even setting aside the way channels are sorted within categories.)

Not that for example discord.js makes a distinction between "rawPosition" (the number given by Discord) and "position" (the actual index position in a list), though their documentation is also not super clear.

Here is my best understanding of channel positions (as with everything about the discord API, there's a ton of misinformation out there):

  • As far as the server is concerned, "position" is just an arbitrary int that gets carried with channel metadata. There's no checking that they're consecutive or don't collide or anything.
  • The Discord client sorts channels for display:
    • first by category
    • then by type (text first, then voice) within the category
    • then by the position value (lowest first) within the category and type
    • then by raw channel ID (earliest first) when category, type, and position value are all the same
  • When the Discord client creates a new channel, it assigns a position value that's 1 + the highest value within the category/type group.
  • When you drag a channel around in the Discord client, in addition to possibly reassigning the category, it assigns a position value that's 1 + the position of the channel just above where it was dragged. All channels lower in the group are renumbered to consecutive numbers after that.
  • Note that all of this might be happening from multiple clients at once.

Deleting or recategorizing channels can easily leave "holes" in the channel numbering. The client will try to avoid dup numbers, but simultaneous updates (race conditions) can lead to them, too. So one should most definitely not assume that the position value is an absolute index within the group.

The discord.py library reports these raw, potentially holey position values as received from the Discord server. When a library user sets the position, the library does this kinda fancy thing which places the channel in the list at that position (relative to other position values), and then bulk-renumbers all the channels in the same category/type batch into a consecutive series.

(Let me know if you'd like a PR...!)

@Rapptz
Copy link
Owner

Rapptz commented Oct 17, 2020

You are correct, this is the explanation I give people when they ask in the help channels whenever something comes up. Documenting this better in the actual documentation site has been a goal for some time but care needs to be taken since it'd be its own article detailing other types of positions as well (such as role positions). That's why this issue is still open, because it's a documentation request that we haven't really gotten to yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs needed Documentation is needed for this change. help appreciated Good issue to work on
Projects
None yet
Development

No branches or pull requests

4 participants