0

The name of this post is confusing but please bear with me.

An example scenario for this would be in discord.py If you are unfamiliar with it please read this example below.

from discord.ext import commands

client = commands.Bot(command_prefix='!')

@client.event
async def on_message(msg):
    print(msg.content)

client.run('token')

While it's somewhat trivial for some of you, I would like an explanation on how this works. I would like to be able to receive the data from an event fired in my program like such below:

import time

class bot:
    class events:
        def on_time_change(ctx):
            return ctx
    def __init__(self):
        while True:
            dispatch(time.time, self.events.on_time_change)
            time.sleep(1)

calls = bot

@calls.events()
def on_time_change(ctx):
    print(ctx) # prints your time dispatched from the init script

Please let me know if this doesn't make any sense, it's my first post, I really need help, thanks!

I've tried searching everywhere and nothing works, I must be wording it wrong.

InSync
  • 4,851
  • 4
  • 8
  • 30
walrus
  • 1
  • I'm not sure what you're after. Do you need [an explanation about decorators](https://stackoverflow.com/q/739654)? Or do you need help regarding creating and handling a custom event (in which case you will need to explain what kind of event it is and how would you dispatch it)? – InSync Jul 18 '23 at 15:34
  • Well I'm trying with stuff like events which I can detect with the events as in my example I gave in post. Meaning I would like something to fire when a change is spotted and be able to detect that fire using an event like as mentioned in my post. – walrus Jul 18 '23 at 15:55
  • From your (pseudo-)code, I think you want to dispatch this event every 1 second. Is that correct? – InSync Jul 18 '23 at 15:57
  • Yes that is correct – walrus Jul 18 '23 at 16:04

3 Answers3

1

The following snippet demonstrate an oversimplified version of an event handling model:

class Event:
  def __init__(self):
    self.handlers = set()

  def register(self, handler):
    if handler in self.handlers:
      raise ValueError('A listener cannot be registered more than once')

    self.handlers.add(handler)

  def dispatch(self):
    for handler in self.handlers:
      handler()

.register() takes in a function and checks if it's already in the set of handlers. If it is, we raise an exception. Else, we add it to the bunch. .dispatch() simply iterates over the set and calls all of those handlers. Since we're using a set, the iteration order is not guaranteed; you can change this by using a more suitable data structure.

We use the class as follow:

event = Event()

@event.register
def listener():
    print('Handler invoked.')

@event.register def listener(): ... is the same as def listener(): ... listener = event.register(listener). We didn't return anything in .register(), so if you were to print listener out you would see None.

Finally, we dispatch the event by calling the .dispatch() method; this works nicely, as expected:

import time

while True:
  event.dispatch()
  time.sleep(1)

'''
Handler invoked.
Handler invoked.
Handler invoked.
...
'''
InSync
  • 4,851
  • 4
  • 8
  • 30
0

I found out how to fix it, thanks for the help!

import time

def test(func):
    def handler():
        while True:
            func()
            time.sleep(1)
    return handler

@test
def output():
    print('test')

output()
walrus
  • 1
0

The easiest way would be using the build-in client.dispatch function. There's no documentation for it sadly.

from discord.ext import commands

client = commands.Bot(command_prefix='!')

@client.command()
async def dispatch_time_change(ctx):
    # first argument is the event name (without the 'on_')
    # the next argument, is the argument that will be passed into the event itself.
    client.dispatch("time_change", ctx)  


@client.event
async def on_time_change(ctx):
    await ctx.send("TIME CHANGE")


client.run("token")

Whenever you use the dispatch_time_change command, it will dispatch your custom event and call it. You can dispatch it from anywhere, as long as you pass the necessary arguments for the event.

Łukasz Kwieciński
  • 14,992
  • 4
  • 21
  • 39