Discord-Autorole wird nicht zugewiesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Phobit
User
Beiträge: 91
Registriert: Freitag 4. Mai 2018, 18:13

Sonntag 12. August 2018, 14:59

Hallo,
mein Discord Bot soll bei Beitritt eines neuen Mitglieds diesem automatisch eine vorher definierte Rolle zuweisen. So sieht der Code aus:

Code: Alles auswählen

@client.event
async def on_member_join(member):
    await client.send_message(member, "**Hey! %s**\n Willkommen auf dem %s Discord Server von %s! \n Viel Spaß!"
                              % (member.name, member.server.name, member.server.owner.mention))
    role = cmd_autorole.get(member.server)
    if role is not None:
        await client.add_roles(member, role)
        try:
            await client.send_message(member, "Dir wurde automatisch die Rolle " + role.mention + "zugewiesen!")
        except Exception:
            await client.send_message(member, "Entschuldigung, der Bot besitzt keine Rechte um dir die Rolle "
                                      + role.name + " zuzuordnen! \nBitte kontaktiere den Besitzer des Servers, "
                                      + member.server.owner.mention + "!")
            raise Exception
und hier der im Code erwähnte cmd_autorole:

Code: Alles auswählen

async def error(content, channel, client):
    await client.send_message(channel, embed=discord.Embed(color=discord.Color.red(), description=content))


async def get(server):
    f = "SETTINGS/" + server.id + "/autorole"
    if path.isfile(f):
        with open(f) as f:
            return discord.utils.get(server.roles, id=f.read())
    else:
        return None
    


async def savefile(id, server):
    if not path.isdir("SETTINGS/" + server.id):
        os.makedirs("SETTINGS/" + server.id)
    with open("SETTINGS/" + server.id + "/autorole", "w") as f:
        f.write(id)
        f.close()
    


async def ex(args, message, client, invoke):
    if len(args) > 0:
        rolename = args.__str__()[1:-1].replace(",", "").replace("'", "")
        print(rolename)
        role = discord.utils.get(message.server.roles, name=rolename)
        if role == None:
            await error("Bitte eine -auf diesem Server existierende- Rolle eingeben", message.channel, client)
        else:
            try:
                await savefile(role.id, message.server)
                await client.send_message(message.channel, embed=discord.Embed(color=discord.Color.green(),
                                                                               description=("Automatische Rolle wurde "
                                                                                            "geändert zu Rolle: %s!"
                                                                                            % role.name)))
            except Exception:
                await error("Unbekannter Fehler beim Speichern der Autorolle!", message.channel, client)
                raise Exception
Also, am Anfang muss der Owner des Server mit ~autorole ROLENAME festelgen, was die Autorolle ist. Ab dann soll automatisch die Rolle einem jedem neuen Mitglied zugewiesen werden. wenn nun ein neues Mitglied joint, wird aber nichts neues zugewiesen, nur dieser Error hier erscheint:

Ignoring exception in on_member_join
Traceback (most recent call last):
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/client.py", line 307, in _run_event
yield from getattr(self, event)(*args, **kwargs)
File "/home/phobit/PycharmProjects/DiscordSippenBot/Discord/Main.py", line 189, in on_member_join
await client.add_roles(member, role)
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/client.py", line 2915, in add_roles
new_roles = utils._unique(role.id for role in itertools.chain(member.roles, roles))
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/utils.py", line 232, in _unique
return [x for x in iterable if not (x in seen or adder(x))]
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/utils.py", line 232, in <listcomp>
return [x for x in iterable if not (x in seen or adder(x))]
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/client.py", line 2915, in <genexpr>
new_roles = utils._unique(role.id for role in itertools.chain(member.roles, roles))
AttributeError: 'coroutine' object has no attribute 'id'
/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/client.py:314: RuntimeWarning: coroutine 'get' was never awaited
pass
Ignoring exception in on_member_join
Traceback (most recent call last):
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/client.py", line 307, in _run_event
yield from getattr(self, event)(*args, **kwargs)
File "/home/phobit/PycharmProjects/DiscordSippenBot/Discord/Main.py", line 189, in on_member_join
await client.add_roles(member, role)
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/client.py", line 2915, in add_roles
new_roles = utils._unique(role.id for role in itertools.chain(member.roles, roles))
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/utils.py", line 232, in _unique
return [x for x in iterable if not (x in seen or adder(x))]
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/utils.py", line 232, in <listcomp>
return [x for x in iterable if not (x in seen or adder(x))]
File "/home/phobit/PycharmProjects/DiscordSippenBot/venv/lib/python3.6/site-packages/discord/client.py", line 2915, in <genexpr>
new_roles = utils._unique(role.id for role in itertools.chain(member.roles, roles))
AttributeError: 'coroutine' object has no attribute 'id'



Ich habe den Code eigentlich aus einem Tutorial, deswegen wundert mich dieser Error.
Der Bot besitzt die Rechte, diese Rolle zuzuornden, falls jemand denkt es liegt daran!
Sirius3
User
Beiträge: 8270
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 12. August 2018, 16:04

@Phobit: weißt Du, was dieses `async` vor dem `def` bedeutet?

Zudem: Pfade setzt man mit `os.path.join` zusammen und nicht mit `+`. Statt mit ispath zu prüfen, ob die Datei existiert (was sowieso nicht 100% funktioniert), besser die Exception IOError abfangen.
Ebenso funktioniert das mit isdir und makedirs in `savefile` nicht 100% zuverlässig. Dafür kennt aber makedirs das Argument exist_ok.

Dass das Verzeichnis SETTINGS relativ zu irgendeinem aktuellen Verzeichnis erzeugt wird, sieht komisch aus.

In `ex` arbeitest Du mit der Stringrepresentation einer Liste, was man nie machen sollte, weil die nur für Debuggingzwecke da ist. Suchst Du einfach nur `rolename = args[0]`?
Phobit
User
Beiträge: 91
Registriert: Freitag 4. Mai 2018, 18:13

Donnerstag 16. August 2018, 09:52

weißt Du, was dieses `async` vor dem `def` bedeutet?
Heisst meines wissens nach dass der Block asyncron ausgeführt wird, alles was nicht mit async und dann mit await ausgeführt wird, wird von Discord einfach ignoriert.
Zudem: Pfade setzt man mit `os.path.join` zusammen und nicht mit `+`. Statt mit ispath zu prüfen, ob die Datei existiert (was sowieso nicht 100% funktioniert), besser die Exception IOError abfangen.
Ebenso funktioniert das mit isdir und makedirs in `savefile` nicht 100% zuverlässig. Dafür kennt aber makedirs das Argument exist_ok.
Das klappt allerdings. Wenn ich die Rolle mit ~autorole ROLENMAE setze, wird in meinem Settings Ordner die passende Datei angelegt. Es hängt jetzt nur an diesem AttributeError!
In `ex` arbeitest Du mit der Stringrepresentation einer Liste, was man nie machen sollte, weil die nur für Debuggingzwecke da ist.
Naja, ich arbeite jetzt seit ca 3 Monaten an diesem Bot, bis jetzt hat ausnahmslos ALLES funktioniert, nur diese Autorole eben funktioniert nicht.
Suchst Du einfach nur `rolename = args[0]`?
Da versteh ich jetzt nicht ganz was du genau meinst, sorry, bin begriffsstuzig :K
Benutzeravatar
__blackjack__
User
Beiträge: 1083
Registriert: Samstag 2. Juni 2018, 10:21

Donnerstag 16. August 2018, 10:14

@Phobit: Auch wenn der Code mit dem Verarbeiten der Zeichenkettenrepräsentation einer Liste funktioniert ist der *falsch*. Das ist undurchsichtig, fehleranfällig, und es bleibt auch die Frage ob das *wirklich* funktioniert, oder ob Dir einfach ein Fehleverhalten noch nicht aufgefallen ist. Die `__str__()`-Methode selbst aufzurufen ist schon ein No-Go.

@Sirius3: Ich denke es wird eher ein ``''.join(args)`` gemacht, eventuell mit einem `map()` und `str` beziehungsweise `repr` um am Ende 100% bei der gleichen Semantik heraus zu kommen, wobei genau das `repr` im jetztigen Ansatz ja *eine* Quelle von Problemen sein kann ­— wenn die Einzelteile mal nicht nur ”Unproblematisches” enthalten.
“Capitalism is the astounding belief that the most wickedest of men will do the most wickedest of things for the greatest good of everyone.” – John Maynard Keynes
Sirius3
User
Beiträge: 8270
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 16. August 2018, 19:11

Phobit hat geschrieben:
Donnerstag 16. August 2018, 09:52
Heisst meines wissens nach dass der Block asyncron ausgeführt wird, alles was nicht mit async und dann mit await ausgeführt wird, wird von Discord einfach ignoriert.
Dass das bei Discord so sein muß, weil es eine asynchrone Bibliothek ist, mag sein, bei `savefile` hast Du aber etwas gemacht, was so nicht funktioniert.
Phobit
User
Beiträge: 91
Registriert: Freitag 4. Mai 2018, 18:13

Montag 20. August 2018, 14:40

achso, darf das savefile also nicht asnyc sein?


EDIT:
Also daran kann es eigentlich nicht liegen, da die Autorole sich ja korrekt abspeichert.
Sirius3
User
Beiträge: 8270
Registriert: Sonntag 21. Oktober 2012, 17:20

Montag 20. August 2018, 22:57

Dann hast Du ›async‹ noch nicht verstanden. Das ist nur syntaktischer Zucker für Generatoren.
Septias
User
Beiträge: 50
Registriert: Freitag 24. Juni 2016, 19:15

Mittwoch 22. August 2018, 14:28

Es gibt einen extra Discord-API-Server, bei dem du eventuell deine Fragen posten kannst (#python_discord-py). Ist auf Englisch, aber du bekommst fast immer nach 2min eine Antwort und dort kennen sich die Meisten auch echt gut aus.

https://discord.gg/discord-api
Phobit
User
Beiträge: 91
Registriert: Freitag 4. Mai 2018, 18:13

Donnerstag 23. August 2018, 15:19

Es gibt einen extra Discord-API-Server, bei dem du eventuell deine Fragen posten kannst (#python_discord-py). Ist auf Englisch, aber du bekommst fast immer nach 2min eine Antwort und dort kennen sich die Meisten auch echt gut aus.
Ah, vielen Dank, aber mitlerweile habe ich eine (temporäre Lösung) für das Problem gefunden:

Code: Alles auswählen

def error(content, channel, client):
    yield from client.send_message(channel, embed=discord.Embed(color=discord.Color.red(), description=content))


def get(server):
    f = "SETTINGS/" + server.id + "/autorole"
    if path.isfile(f):
        with open(f) as f:
            return discord.utils.get(server.roles, id=f.read())
    else:
        return None
    


def savefile(id, server):
    if not path.isdir("SETTINGS/" + server.id):
        os.makedirs("SETTINGS/" + server.id)
    with open("SETTINGS/" + server.id + "/autorole", "w") as f:
        f.write(id)
        f.close()
    


def ex(args, message, client, invoke):
    if len(args) > 0:
        rolename = args.__str__()[1:-1].replace(",", "").replace("'", "")
        print(rolename)
        role = discord.utils.get(message.server.roles, name=rolename)
        if role == None:
            yield from error("Bitte eine -auf diesem Server existierende- Rolle eingeben", message.channel, client)
        else:
            try:
                savefile(role.id, message.server)
                yield from client.send_message(message.channel, embed=discord.Embed(color=discord.Color.green(),
                                                                               description=("Automatische Rolle wurde "
                                                                                            "geändert zu Rolle: %s!"
                                                                            % role.name)))
            except Exception:
                yield from error("Unbekannter Fehler beim Speichern der Autorolle!", message.channel, client)
                 raise Exception
Hier noch der Auschnitt aus dem Hauptprogramm:

Code: Alles auswählen

@client.event
@asyncio.coroutine
def on_member_join(member):
    yield from client.send_message(AllgemeinSippe, greeting + member.name + "!")
    yield from client.send_message(member, "**Hey! %s**\n Willkommen auf dem %s Discord Server von %s! \n Viel Spaß!"
                              % (member.name, member.server.name, member.server.owner.mention))
    role = cmd_autorole.get(member.server)
    if not role == None:
        yield from client.add_roles(member, role)
        try:
            yield from client.send_message(member, "Dir wurde automatisch die Rolle " + role.name + " zugewiesen!")
        except Exception:
            yield from client.send_message(member, "Entschuldigung, der Bot besitzt keine Rechte um dir die Rolle "
                                      + role.name + " zuzuordnen! \nBitte kontaktiere den Besitzer des Servers, "
                                      + member.server.owner.mention + "!")
            asyncio.sleep(3)
            raise Exception 
Kann mir vllt jemand anhand dieses Codes sagen, wo bei mir mit async der Fehler war? Laut dem Tutorial, aus dem ich alles hier hab, muss es mit async möglich sein!
Sirius3
User
Beiträge: 8270
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 23. August 2018, 18:58

Warum hast Du jetzt alle `async` gelöscht und alle `await` durch `yield from` ersetzt? Wenn Du jetzt noch herausfindest, wo sich die beiden Methoden unterscheiden, weißt Du auch, warum `savefile` nicht async sein darf. Andere Sachen, die Du zum Schlechteren verändert ist, ist .z.b das `not role == None`. Warum?

Was ist denn nun `args` in der Funktion `ex`? Sollteder das jetzt `args[0]` oder `' '.join(args)` sein?
Der autorole-Dateinamen wird an vier verschiedenen Stellen erzeugt, das sollte nur eine sein. Pfade setzt man mit os.path.join zusammen.
Für die anderen Strings benutzt man format statt +.

Du hast noch einen Einrückfehler.
Phobit
User
Beiträge: 91
Registriert: Freitag 4. Mai 2018, 18:13

Freitag 24. August 2018, 15:56

Warum hast Du jetzt alle `async` gelöscht und alle `await` durch `yield from` ersetzt?
Wie schon erwähnt, habe ich als Vorlage ein tutorial genommen. In dem Tutorial wurde yield from benutzt, und irgendwann stieg der jenige aber auf async und await um, ohne zu zeigen was ich austauschen müsste. Deshalb hab ich jetzt wieder das yield from benutzt, da ich offensichtlich einen Fehler in den awaits/asyncs habe.
Andere Sachen, die Du zum Schlechteren verändert ist, ist .z.b das `not role == None`. Warum?
Wie gesagt, Tutorial. Aber dort verstehe ich auch das Problem nicht, immerhin funktioniert es ja, weil:
"Wenn nicht dir Rolle nichts ist" ergibt meiner Meinung nach Sinn.
Was ist denn nun `args` in der Funktion `ex`? Sollteder das jetzt `args[0]` oder `' '.join(args)` sein?
Die args sind alles, was bei einem Befehl, der im Discord ausgeführt wird, hinter dem Befehl steht, was hier ausgelesen werden muss, da der Befehl "~autorole ROLENAME" ist, und ROLENAME ist das arg das ausgelesen werden muss.
Benutzeravatar
__blackjack__
User
Beiträge: 1083
Registriert: Samstag 2. Juni 2018, 10:21

Freitag 24. August 2018, 16:35

@Phobit: „Wenn nicht dir Rolle nichts ist“ ist ziemlich verquer und unverständlich ausgedrückt. Normalerweise sagt man da „Wenn die Rolle nicht ”Nichts” ist“, also ``role is not None``. Hier ``is not`` statt ``!=`` weil `None` nur ein einiges mal als Objekt existiert (Singleton) und man deshalb auf Objektidentität statt auf Gleichheit prüfen kann.
“Capitalism is the astounding belief that the most wickedest of men will do the most wickedest of things for the greatest good of everyone.” – John Maynard Keynes
Phobit
User
Beiträge: 91
Registriert: Freitag 4. Mai 2018, 18:13

Freitag 24. August 2018, 17:33

Heisst doch, dass es egal ist wie ich es vergleiche, also ist if not role == None eigentlich das selbe, nur unschöner ausgedrückt, mir würde jetzt kein Fall einfallen bei dem das nen Error werfen könnte...
Benutzeravatar
__blackjack__
User
Beiträge: 1083
Registriert: Samstag 2. Juni 2018, 10:21

Freitag 24. August 2018, 17:41

Nein, das führt so direkt nicht zu einem Fehler beim ausführen, aber egal ist es deswegen trotzdem nicht. Du schreibst Quelltext nicht für nur für den Rechner sondern auch für Menschen, inklusive Dir selbst, und da kann das dann zu falschen Vorstellungen davon führen was der Code macht, oder zumindest das Verständnis erschweren. Was dann bei Programmänderungen zu Fehlern führen kann.
“Capitalism is the astounding belief that the most wickedest of men will do the most wickedest of things for the greatest good of everyone.” – John Maynard Keynes
Antworten