quickstart¶
Overview¶
The minevent
event system is composed of three main components:
- an event
- an event handler
- an event manager
It is a synchronous system i.e. only one event and event handler are executed at the same time.
This page presents the design used in minevent
, but other designs exist.
The proposed design was not designed to work in all the scenarios, so it is highly recommended to
read the documentation to understand if it fits your needs/requirements before to use it.
Event¶
In minevent
, an event is a string that represents something happening.
The event is represented by the event name.
For example, it is possible to write the following line to define an event that happens after the
training is completed.
my_event = "training completed"
Event handler¶
In minevent
, an event handler is a piece a code that is executed when an even happened.
An event handler must have two methods:
handle
which executes a piece of code when the event happens.equal
which is used to compare two event handlers.
minevent
provides two event handlers:
EventHandler
which is a simple event handlerConditionalEventHandler
which is an extension ofEventHandler
to execute the logic only when a condition is true.
Basic event handler¶
Let's assume we want to create an event handler to say hello when an event is fired.
It is possible to implement this scenario as follow by using minvent.EventHandler
.
>>> from minevent import EventHandler
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> handler = EventHandler(hello_handler)
>>> handler.handle()
Hello!
Event handler with arguments¶
The previous example has no arguments.
It is also possible to provide some arguments to customize the event handler.
The arguments can be given as positional arguments using handler_args
:
>>> from minevent import EventHandler
>>> def hello_handler(name: str, day: str) -> None:
... print(f"Hello {name}! Happy {day}!")
...
>>> handler = EventHandler(hello_handler, handler_args=("Bob", "Monday"))
>>> handler.handle()
Hello Bob! Happy Monday!
It is also possible to give the arguments as keyword arguments using handler_kwargs
:
>>> from minevent import EventHandler
>>> def hello_handler(name: str, day: str) -> None:
... print(f"Hello {name}! Happy {day}!")
...
>>> handler = EventHandler(hello_handler, handler_kwargs={"name": "Bob", "day": "Monday"})
>>> handler.handle()
Hello Bob! Happy Monday!
It is also possible to use handler_args
and handler_kwargs
:
>>> from minevent import EventHandler
>>> def hello_handler(name: str, day: str) -> None:
... print(f"Hello {name}! Happy {day}!")
...
>>> handler = EventHandler(
... hello_handler, handler_args=["Bob"], handler_kwargs={"day": "Monday"}
... )
>>> handler.handle()
Hello Bob! Happy Monday!
It is possible to define event handlers with a large range of functions.
For example, it is possible to implement the same logic by using directly print
:
>>> from minevent import EventHandler
>>> handler = EventHandler(print, handler_args=("Hello Bob! Happy Monday!",))
>>> handler.handle()
Hello Bob! Happy Monday!
Event handler with condition¶
It is possible to define an event handler that is executed when a condition is true. The following example shows how to define an event handler where the logic is executed every three calls.
>>> from minevent import ConditionalEventHandler, PeriodicCondition
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> handler = ConditionalEventHandler(hello_handler, PeriodicCondition(freq=3))
>>> handler.handle()
Hello!
>>> handler.handle()
>>> handler.handle()
>>> handler.handle()
Hello!
PeriodicCondition
is a condition implemented in minevent
to execute an event handler with a
periodic pattern.
It is also possible to implement custom conditions.
If the condition returns True
, the logic associated to the event handler is executed, otherwise
the logic associated to the event handler is not executed.
Event handler comparison¶
It is possible to compare event handlers by using the equal
method.
Two EventHandler
s are equal if they have the same handler and the same arguments:
>>> from minevent import EventHandler
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> handler = EventHandler(hello_handler)
>>> handler.equal(EventHandler(hello_handler))
True
>>> handler.equal(EventHandler(print, handler_args=("Hello Bob! Happy Monday!",)))
False
Two EventHandler
s are equal if they have the same handler, the same arguments and the same
condition:
>>> from minevent import ConditionalEventHandler, PeriodicCondition
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> handler = ConditionalEventHandler(hello_handler, PeriodicCondition(freq=3))
>>> handler.equal(ConditionalEventHandler(hello_handler, PeriodicCondition(freq=3)))
True
>>> handler.equal(ConditionalEventHandler(hello_handler, PeriodicCondition(freq=2)))
False
Event manager¶
- Overview of the event manager
- Create an event manager
- Add an event handler
- Check the presence of an event handler
- Fire an event
- Remove an event handler
- Reset the event manager
- Internals
Overview of the event manager¶
As explained by its name, the goal of the event manager is to manage event handlers. The event manager supports the following functionalities:
- adding an event handler
- firing all the event handlers associated to an event.
- removing an event handler from an event
Create an event manager¶
To use the event system, it is important to create an event manager.
minevent
implements an event manager, but it is possible to implement and use other compatible
event managers.
This documentation uses the default event manager implemented in minevent
.
To create an event manager, you can write:
>>> from minevent import EventManager
>>> manager = EventManager()
>>> manager
EventManager(
(event_handlers):
(last_triggered_event): None
)
The main pieces of information about the experiment manager state are the list of event handlers for
each event name, and the last fired event name.
The event manager is empty, so it shows there is no event handler.
In this example, there was no event fired so the last fired event name is None
.
Add an event handler¶
This section describes how to add an event handler to an event manager.
The method to add an event handler to the event manager is add_event_handler
.
There are several approaches to add an event handler.
The simplest approach requires an event and an event handler.
The following example shows how to add a hello_handler
handler to the 'my_event'
event.
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): None
)
You can see there is a registered event handler for the event name my_event
.
It is possible to add an event handler that takes some input arguments. The following example shows how to add an event handler with some positional arguments.
>>> from minevent import EventHandler, EventManager
>>> def hello_handler(first_name: str, last_name: str) -> None:
... print(f"Hello. I am {last_name}, {first_name} {last_name}")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler, ("John", "Smith")))
>>> manager.add_event_handler("my_event", EventHandler(hello_handler, ("Jane", "Doe")))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ('John', 'Smith')
(handler_kwargs): {}
)
(1): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ('Jane', 'Doe')
(handler_kwargs): {}
)
(last_triggered_event): None
)
For a given event, the event handlers are ordered by using the order of addition.
The event handler (0)
was added before the event handler (1)
.
Internally, each event uses a list to store the registered event handlers.
It is possible to add the same event handler multiple times:
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(1): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): None
)
Check the presence of an event handler¶
It is possible to check if an event handler is in the event manager by using the has_event_handler
method.
Sometimes, it may be important to check if an event handler is not already added before to add it.
The following code shows how to check if the hello_handler
handler is registered at least one time
in the event manager:
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.has_event_handler(EventHandler(hello_handler))
False
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager.has_event_handler(EventHandler(hello_handler))
True
Note that it is not necessary to specify an event.
If no event is specified, this method checks if the handler is present in any of the events.
It is possible to specify an event to check if a handler is registered for a given event.
The following code shows how to check if the hello_handler
handler is registered for
the 'my_event'
event:
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.has_event_handler(EventHandler(hello_handler), "my_event")
False
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager.has_event_handler(EventHandler(hello_handler), "my_event")
True
>>> manager.has_event_handler(EventHandler(hello_handler), "my_other_event")
False
If you want to add an event handler only once, you can write something like:
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> for _ in range(5):
... if not manager.has_event_handler(EventHandler(hello_handler), "my_event"):
... manager.add_event_handler("my_event", EventHandler(hello_handler))
...
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): None
)
The hello_handler
handler has been added only one time to the 'my_event'
event.
Fire an event¶
This section describes how to fire an event.
As explained above, it is possible to add a handler to an event.
Then, we want to execute the handler when the event is fired.
The following example shows how to fire the hello_handler
for the event 'my_event'
:
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): None
)
>>> manager.trigger_event("my_event")
Hello!
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): my_event
)
You can note that the last fired event name has been updated.
The current last fired event name is 'my_event'
.
The event manager uses the arguments that were given when the event handler was added.
>>> from minevent import EventHandler, EventManager
>>> def hello_handler(first_name: str, last_name: str) -> None:
... print(f"Hello. I am {first_name} {last_name}")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler, ("John", "Smith")))
>>> manager.add_event_handler("my_event", EventHandler(hello_handler, ("Jane", "Doe")))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ('John', 'Smith')
(handler_kwargs): {}
)
(1): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ('Jane', 'Doe')
(handler_kwargs): {}
)
(last_triggered_event): None
)
>>> manager.trigger_event("my_event")
Hello. I am John Smith
Hello. I am Jane Doe
As explained above, it is possible to add a condition to control when to execute the handler.
The following shows how to execute the hello_handler
every 3 'my_event'
events.
>>> from minevent import ConditionalEventHandler, PeriodicCondition, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.add_event_handler(
... "my_event", ConditionalEventHandler(hello_handler, PeriodicCondition(freq=3))
... )
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): ConditionalEventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
(condition): PeriodicCondition(freq=3, step=0)
)
(last_triggered_event): None
)
>>> for i in range(10):
... print(f"i={i}")
... manager.trigger_event("my_event")
...
i=0
Hello!
i=1
i=2
i=3
Hello!
i=4
i=5
i=6
Hello!
i=7
i=8
i=9
Hello!
The trigger_event
method does nothing if there is no event handler registered for the event:
>>> from minevent import EventManager
>>> manager = EventManager()
>>> manager.trigger_event("my_event")
Remove an event handler¶
A previous section describes how to add an event handler, but sometimes it is useful to remove an
event handler.
The method remove_event_handler
allows to remove an event handler from the event manager.
As explained above, the event handler is identified by an event name and a handler.
The following example shows how to add and remove an event handler:
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): None
)
>>> manager.remove_event_handler("my_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(last_triggered_event): None
)
If there are multiple event handlers that match, they are all removed from the event manager:
>>> from minevent import (
... ConditionalEventHandler,
... PeriodicCondition,
... EventHandler,
... EventManager,
... )
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager.add_event_handler(
... "my_event", ConditionalEventHandler(hello_handler, PeriodicCondition(freq=3))
... )
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(1): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(2): ConditionalEventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
(condition): PeriodicCondition(freq=3, step=0)
)
(last_triggered_event): None
)
>>> manager.remove_event_handler("my_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): ConditionalEventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
(condition): PeriodicCondition(freq=3, step=0)
)
(last_triggered_event): None
)
If a handler is used for multiple events, only the handler associated to the event are removed:
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager.add_event_handler("my_other_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(my_other_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): None
)
>>> manager.remove_event_handler("my_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(my_other_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): None
)
A RuntimeError
exception is raised if you try to remove an event handler that does not exist.
Reset the event manager¶
It is possible to reset the event manager with the reset
method. It removes all the event handlers
and set the last
fired event name to None
. It is equivalent to create a new experiment manager.
>>> from minevent import EventHandler, EventManager
>>> def hello_handler() -> None:
... print("Hello!")
...
>>> manager = EventManager()
>>> manager.add_event_handler("my_event", EventHandler(hello_handler))
>>> manager.add_event_handler("my_other_event", EventHandler(hello_handler))
>>> manager
EventManager(
(event_handlers):
(my_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(my_other_event):
(0): EventHandler(
(handler): <function hello_handler at 0x...>
(handler_args): ()
(handler_kwargs): {}
)
(last_triggered_event): None
)
>>> manager.reset()
>>> manager
EventManager(
(event_handlers):
(last_triggered_event): None
)