action.emitter module

Source code
from collections import defaultdict
from typing import Callable, List
from weakref import WeakSet

from gevent import spawn, Greenlet


class ActionEmitter:
    """
    The class that deals with emitting and listening

    This in the class that is used by `action.client.Action` to trigger events. You can use this class by it self if
    you'd like, but if that's the only reason you're using this library I would suggest you re-create this class
    yourself.

    Attributes
    ----------
    listeners : defaultdict[str -> List[Callable]]
        The dict that carries all listeners that were attached.
    only_once : defaultdict[str -> List[Callable]]
        The dict that contains information on listeners that want to be removed the first time they're called.
    active_events : WeakSet[gevent.Greenlet]
        A set of weak refs to greenlets that have been spawned via emits
    """

    def __init__(self):
        self.listeners = defaultdict(list)
        self.only_once = defaultdict(list)  # I wish there was a better way, will update if I can think of something
        self.active_events = WeakSet()

    def listen(self, name: str, func: Callable = None) -> Callable:
        """
        Register the function as a listener

        This method will add the function as a listener, so that it may listen to events emitted with the specified
        name. You should use it like this when you can::

            @emitter.listen("HelloWorld")
            def hello_world():
              ...

        Or like this when you can't::

            def hello_world():
                ...

            emitter.listen("HelloWorld", hello_world)

        But whatever you do, *don't* pass in a function, and use it as a decorator at the same time!

        Parameters
        ----------
        name : str
            The name of the events to listen to
        func : Callable, optional
            Only use this if you are unable to use the listen command as a decorator

        Returns
        -------
        function : Callable
            Either the function you passed in, or a function wrapper if used as a decorator
        """
        def func_wrapper(func):
            self.listeners[name].append(func)
            return func

        if func is not None:
            return func_wrapper(func)
        return func_wrapper

    def listen_once(self, name: str, func: Callable = None) -> Callable:
        """
        Register a function that will be removed when triggered

        This method will behave exactly the same was as `action.emitter.ActionEmitter.listen`, however after the
        first time the listener is triggered, it will also be removed. This is useful when you need something to be
        setup, but only once.

        Parameters
        ----------
        name : str
            The name of the event it will listen for
        func : Callable
            The listener, see `action.emitter.ActionEmitter.listen` for more details.

        Returns
        -------
        function : Callable
            See `action.emitter.ActionEmitter.listen` for more details.
        """
        if func is None:
            def func_wrap(func):
                return self.listen_once(name, func)
            return func_wrap

        self.only_once[name].append(func)
        self.listen(name, func)

        return func

    def emit(self, name: str, *args, **kwargs) -> List[Greenlet]:
        """
        Trigger listeners for a specific event

        This method will instantly trigger all functions that are listening to the provided event. If you actually
        wanted to trigger an event at another time, see `action.client.Action` for help with that. It will spawn the
        listeners are greenlets, so this method is non-blocking.

        Parameters
        ----------
        name : str
            The name of the event that is being emitted
        *args : Any
            Args that will be provided to the listeners
        **kwargs : str, Any
            Kwargs that will be provided to the listeners

        Returns
        -------
        greenlets : List[gevent.Greenlet]
            A list of listeners that have been spawned
        """
        greenlets = []
        for callback in self.listeners[name]:
            if callback in self.only_once[name]:
                self.only_once[name].remove(callback)
                self.remove_listener(name, callback)
            greenlets.append(spawn(callback, *args, **kwargs))
        self.active_events.update(greenlets)
        return greenlets

    def remove_listener(self, name: str, func: Callable = None):
        """
        Remove a listener

        This command is used to remove either one or multiple listeners. If you want to remove all listeners
        connected to a certain event, call this method without a function:

            emitter.remove_listener("join")

        However if you only want to remove a specific listener from an event, provide that function:

            @emitter.listen("join")
            def on_join():
              ...

            emitter.remove_listener("join", on_join)

        Parameters
        ----------
        name : str
            The name of the event you'll be removing (from)
        func : Callable, optional
            The specific listener you're removing

        Raises
        ------
        ValueError
            This error will be raised if you try and remove a specific function that's not a listener
        """
        if func is None:
            self.listeners[name].clear()
        else:
            self.listeners[name].remove(func)

    def remove_all(self):
        """
        Remove all the listeners

        This does exactly what it says. It will remove all listeners, no matter the event it's attached to.
        """
        self.listeners.clear()

Classes

class ActionEmitter

The class that deals with emitting and listening

This in the class that is used by Action to trigger events. You can use this class by it self if you'd like, but if that's the only reason you're using this library I would suggest you re-create this class yourself.

Attributes

listeners : defaultdict[str -> List[Callable]]
The dict that carries all listeners that were attached.
only_once : defaultdict[str -> List[Callable]]
The dict that contains information on listeners that want to be removed the first time they're called.
active_events : WeakSet[gevent.Greenlet]
A set of weak refs to greenlets that have been spawned via emits
Source code
class ActionEmitter:
    """
    The class that deals with emitting and listening

    This in the class that is used by `action.client.Action` to trigger events. You can use this class by it self if
    you'd like, but if that's the only reason you're using this library I would suggest you re-create this class
    yourself.

    Attributes
    ----------
    listeners : defaultdict[str -> List[Callable]]
        The dict that carries all listeners that were attached.
    only_once : defaultdict[str -> List[Callable]]
        The dict that contains information on listeners that want to be removed the first time they're called.
    active_events : WeakSet[gevent.Greenlet]
        A set of weak refs to greenlets that have been spawned via emits
    """

    def __init__(self):
        self.listeners = defaultdict(list)
        self.only_once = defaultdict(list)  # I wish there was a better way, will update if I can think of something
        self.active_events = WeakSet()

    def listen(self, name: str, func: Callable = None) -> Callable:
        """
        Register the function as a listener

        This method will add the function as a listener, so that it may listen to events emitted with the specified
        name. You should use it like this when you can::

            @emitter.listen("HelloWorld")
            def hello_world():
              ...

        Or like this when you can't::

            def hello_world():
                ...

            emitter.listen("HelloWorld", hello_world)

        But whatever you do, *don't* pass in a function, and use it as a decorator at the same time!

        Parameters
        ----------
        name : str
            The name of the events to listen to
        func : Callable, optional
            Only use this if you are unable to use the listen command as a decorator

        Returns
        -------
        function : Callable
            Either the function you passed in, or a function wrapper if used as a decorator
        """
        def func_wrapper(func):
            self.listeners[name].append(func)
            return func

        if func is not None:
            return func_wrapper(func)
        return func_wrapper

    def listen_once(self, name: str, func: Callable = None) -> Callable:
        """
        Register a function that will be removed when triggered

        This method will behave exactly the same was as `action.emitter.ActionEmitter.listen`, however after the
        first time the listener is triggered, it will also be removed. This is useful when you need something to be
        setup, but only once.

        Parameters
        ----------
        name : str
            The name of the event it will listen for
        func : Callable
            The listener, see `action.emitter.ActionEmitter.listen` for more details.

        Returns
        -------
        function : Callable
            See `action.emitter.ActionEmitter.listen` for more details.
        """
        if func is None:
            def func_wrap(func):
                return self.listen_once(name, func)
            return func_wrap

        self.only_once[name].append(func)
        self.listen(name, func)

        return func

    def emit(self, name: str, *args, **kwargs) -> List[Greenlet]:
        """
        Trigger listeners for a specific event

        This method will instantly trigger all functions that are listening to the provided event. If you actually
        wanted to trigger an event at another time, see `action.client.Action` for help with that. It will spawn the
        listeners are greenlets, so this method is non-blocking.

        Parameters
        ----------
        name : str
            The name of the event that is being emitted
        *args : Any
            Args that will be provided to the listeners
        **kwargs : str, Any
            Kwargs that will be provided to the listeners

        Returns
        -------
        greenlets : List[gevent.Greenlet]
            A list of listeners that have been spawned
        """
        greenlets = []
        for callback in self.listeners[name]:
            if callback in self.only_once[name]:
                self.only_once[name].remove(callback)
                self.remove_listener(name, callback)
            greenlets.append(spawn(callback, *args, **kwargs))
        self.active_events.update(greenlets)
        return greenlets

    def remove_listener(self, name: str, func: Callable = None):
        """
        Remove a listener

        This command is used to remove either one or multiple listeners. If you want to remove all listeners
        connected to a certain event, call this method without a function:

            emitter.remove_listener("join")

        However if you only want to remove a specific listener from an event, provide that function:

            @emitter.listen("join")
            def on_join():
              ...

            emitter.remove_listener("join", on_join)

        Parameters
        ----------
        name : str
            The name of the event you'll be removing (from)
        func : Callable, optional
            The specific listener you're removing

        Raises
        ------
        ValueError
            This error will be raised if you try and remove a specific function that's not a listener
        """
        if func is None:
            self.listeners[name].clear()
        else:
            self.listeners[name].remove(func)

    def remove_all(self):
        """
        Remove all the listeners

        This does exactly what it says. It will remove all listeners, no matter the event it's attached to.
        """
        self.listeners.clear()

Methods

def __init__(self)

Initialize self. See help(type(self)) for accurate signature.

Source code
def __init__(self):
    self.listeners = defaultdict(list)
    self.only_once = defaultdict(list)  # I wish there was a better way, will update if I can think of something
    self.active_events = WeakSet()
def emit(self, name, *args, **kwargs)

Trigger listeners for a specific event

This method will instantly trigger all functions that are listening to the provided event. If you actually wanted to trigger an event at another time, see Action for help with that. It will spawn the listeners are greenlets, so this method is non-blocking.

Parameters

name : str
The name of the event that is being emitted
*args : Any
Args that will be provided to the listeners
**kwargs : str, Any
Kwargs that will be provided to the listeners

Returns

greenlets : List[gevent.Greenlet]
A list of listeners that have been spawned
Source code
def emit(self, name: str, *args, **kwargs) -> List[Greenlet]:
    """
    Trigger listeners for a specific event

    This method will instantly trigger all functions that are listening to the provided event. If you actually
    wanted to trigger an event at another time, see `action.client.Action` for help with that. It will spawn the
    listeners are greenlets, so this method is non-blocking.

    Parameters
    ----------
    name : str
        The name of the event that is being emitted
    *args : Any
        Args that will be provided to the listeners
    **kwargs : str, Any
        Kwargs that will be provided to the listeners

    Returns
    -------
    greenlets : List[gevent.Greenlet]
        A list of listeners that have been spawned
    """
    greenlets = []
    for callback in self.listeners[name]:
        if callback in self.only_once[name]:
            self.only_once[name].remove(callback)
            self.remove_listener(name, callback)
        greenlets.append(spawn(callback, *args, **kwargs))
    self.active_events.update(greenlets)
    return greenlets
def listen(self, name, func=None)

Register the function as a listener

This method will add the function as a listener, so that it may listen to events emitted with the specified name. You should use it like this when you can::

@emitter.listen("HelloWorld")
def hello_world():
  ...

Or like this when you can't::

def hello_world():
    ...

emitter.listen("HelloWorld", hello_world)

But whatever you do, don't pass in a function, and use it as a decorator at the same time!

Parameters

name : str
The name of the events to listen to
func : Callable, optional
Only use this if you are unable to use the listen command as a decorator

Returns

function : Callable
Either the function you passed in, or a function wrapper if used as a decorator
Source code
def listen(self, name: str, func: Callable = None) -> Callable:
    """
    Register the function as a listener

    This method will add the function as a listener, so that it may listen to events emitted with the specified
    name. You should use it like this when you can::

        @emitter.listen("HelloWorld")
        def hello_world():
          ...

    Or like this when you can't::

        def hello_world():
            ...

        emitter.listen("HelloWorld", hello_world)

    But whatever you do, *don't* pass in a function, and use it as a decorator at the same time!

    Parameters
    ----------
    name : str
        The name of the events to listen to
    func : Callable, optional
        Only use this if you are unable to use the listen command as a decorator

    Returns
    -------
    function : Callable
        Either the function you passed in, or a function wrapper if used as a decorator
    """
    def func_wrapper(func):
        self.listeners[name].append(func)
        return func

    if func is not None:
        return func_wrapper(func)
    return func_wrapper
def listen_once(self, name, func=None)

Register a function that will be removed when triggered

This method will behave exactly the same was as ActionEmitter.listen(), however after the first time the listener is triggered, it will also be removed. This is useful when you need something to be setup, but only once.

Parameters

name : str
The name of the event it will listen for
func : Callable
The listener, see ActionEmitter.listen() for more details.

Returns

function : Callable
See ActionEmitter.listen() for more details.
Source code
def listen_once(self, name: str, func: Callable = None) -> Callable:
    """
    Register a function that will be removed when triggered

    This method will behave exactly the same was as `action.emitter.ActionEmitter.listen`, however after the
    first time the listener is triggered, it will also be removed. This is useful when you need something to be
    setup, but only once.

    Parameters
    ----------
    name : str
        The name of the event it will listen for
    func : Callable
        The listener, see `action.emitter.ActionEmitter.listen` for more details.

    Returns
    -------
    function : Callable
        See `action.emitter.ActionEmitter.listen` for more details.
    """
    if func is None:
        def func_wrap(func):
            return self.listen_once(name, func)
        return func_wrap

    self.only_once[name].append(func)
    self.listen(name, func)

    return func
def remove_all(self)

Remove all the listeners

This does exactly what it says. It will remove all listeners, no matter the event it's attached to.

Source code
def remove_all(self):
    """
    Remove all the listeners

    This does exactly what it says. It will remove all listeners, no matter the event it's attached to.
    """
    self.listeners.clear()
def remove_listener(self, name, func=None)

Remove a listener

This command is used to remove either one or multiple listeners. If you want to remove all listeners connected to a certain event, call this method without a function:

emitter.remove_listener("join")

However if you only want to remove a specific listener from an event, provide that function:

@emitter.listen("join")
def on_join():
  ...

emitter.remove_listener("join", on_join)

Parameters

name : str
The name of the event you'll be removing (from)
func : Callable, optional
The specific listener you're removing

Raises

ValueError
This error will be raised if you try and remove a specific function that's not a listener
Source code
def remove_listener(self, name: str, func: Callable = None):
    """
    Remove a listener

    This command is used to remove either one or multiple listeners. If you want to remove all listeners
    connected to a certain event, call this method without a function:

        emitter.remove_listener("join")

    However if you only want to remove a specific listener from an event, provide that function:

        @emitter.listen("join")
        def on_join():
          ...

        emitter.remove_listener("join", on_join)

    Parameters
    ----------
    name : str
        The name of the event you'll be removing (from)
    func : Callable, optional
        The specific listener you're removing

    Raises
    ------
    ValueError
        This error will be raised if you try and remove a specific function that's not a listener
    """
    if func is None:
        self.listeners[name].clear()
    else:
        self.listeners[name].remove(func)