# Buggy code
def add_event_handler(self, event_name: Any, handler: Callable, *args, **kwargs):
    """Add an event handler to be executed when the specified event is fired.

    Args:
        event_name: An event or a list of events to attach the handler. Valid events are
            from :class:`~ignite.engine.Events` or any `event_name` added by
            :meth:`~ignite.engine.Engine.register_events`.
        handler (callable): the callable event handler that should be invoked. No restrictions on its signature.
            The first argument can be optionally `engine`, the :class:`~ignite.engine.Engine` object, handler is
            bound to.
        *args: optional args to be passed to `handler`.
        **kwargs: optional keyword args to be passed to `handler`.

    Note:
        Note that other arguments can be passed to the handler in addition to the `*args` and  `**kwargs`
        passed here, for example during :attr:`~ignite.engine.Events.EXCEPTION_RAISED`.

    Returns:
        :class:`~ignite.engine.RemovableEventHandle`, which can be used to remove the handler.

    Example usage:

    .. code-block:: python

        engine = Engine(process_function)

        def print_epoch(engine):
            print("Epoch: {}".format(engine.state.epoch))

        engine.add_event_handler(Events.EPOCH_COMPLETED, print_epoch)

        events_list = Events.EPOCH_COMPLETED | Events.COMPLETED

        def execute_something():
            # do some thing not related to engine
            pass

        engine.add_event_handler(events_list, execute_something)

    Note:
        Since v0.3.0, Events become more flexible and allow to pass an event filter to the Engine.
        See :class:`~ignite.engine.Events` for more details.

    """
    if isinstance(event_name, EventsList):
        for e in event_name:
            self.add_event_handler(e, handler, *args, **kwargs)
        return RemovableEventHandle(event_name, handler, self)
    if (
        isinstance(event_name, CallableEventWithFilter)
        and event_name.filter != CallableEventWithFilter.default_event_filter
    ):
        event_filter = event_name.filter
        handler = Engine._handler_wrapper(handler, event_name, event_filter)

    if event_name not in self._allowed_events:
        self.logger.error(
            "attempt to add event handler to an invalid event %s.", event_name
        )
        raise ValueError(
            "Event {} is not a valid event for this Engine.".format(event_name)
        )

    event_args = (Exception(),) if event_name == Events.EXCEPTION_RAISED else ()
    try:
        _check_signature(handler, "handler", self, *(event_args + args), **kwargs)
        self._event_handlers[event_name].append((handler, (self,) + args, kwargs))
    except ValueError:
        _check_signature(handler, "handler", *(event_args + args), **kwargs)
        self._event_handlers[event_name].append((handler, args, kwargs))
    self.logger.debug("added handler for event %s.", event_name)

    return RemovableEventHandle(event_name, handler, self)


# Traceback (TypeError)
TypeErrorTraceback (most recent call last)
<ipython-input-13-832efed482dd> in <module>
14
15 e.add_event_handler(Events.ITERATION_COMPLETED(every=2), f4)
---> 16 e.fire_event(Events.ITERATION_COMPLETED)
17 e.fire_event(Events.ITERATION_COMPLETED)

/opt/conda/lib/python3.7/site-packages/ignite/engine/engine.py in fire_event(self, event_name)
414
415         """
--> 416         return self._fire_event(event_name)
417
418     def terminate(self) -> None:

/opt/conda/lib/python3.7/site-packages/ignite/engine/engine.py in _fire_event(self, event_name, *event_args, **event_kwargs)
391                 kwargs.update(event_kwargs)
392                 first, others = ((args[0],), args[1:]) if (args and args[0] == self) else ((), args)
--> 393                 func(*first, *(event_args + others), **kwargs)
394
395     def fire_event(self, event_name: Any) -> None:

/opt/conda/lib/python3.7/site-packages/ignite/engine/engine.py in wrapper(engine, *args, **kwargs)
203             event = engine.state.get_event_attrib_value(event_name)
204             if event_filter(engine, event):
--> 205                 return handler(engine, *args, **kwargs)
206
207         # setup input handler as parent to make has_event_handler work

TypeError: f4() takes 0 positional arguments but 1 was given

# Fixed code
def add_event_handler(self, event_name: Any, handler: Callable, *args, **kwargs):
    """Add an event handler to be executed when the specified event is fired.

    Args:
        event_name: An event or a list of events to attach the handler. Valid events are
            from :class:`~ignite.engine.Events` or any `event_name` added by
            :meth:`~ignite.engine.Engine.register_events`.
        handler (callable): the callable event handler that should be invoked. No restrictions on its signature.
            The first argument can be optionally `engine`, the :class:`~ignite.engine.Engine` object, handler is
            bound to.
        *args: optional args to be passed to `handler`.
        **kwargs: optional keyword args to be passed to `handler`.

    Note:
        Note that other arguments can be passed to the handler in addition to the `*args` and  `**kwargs`
        passed here, for example during :attr:`~ignite.engine.Events.EXCEPTION_RAISED`.

    Returns:
        :class:`~ignite.engine.RemovableEventHandle`, which can be used to remove the handler.

    Example usage:

    .. code-block:: python

        engine = Engine(process_function)

        def print_epoch(engine):
            print("Epoch: {}".format(engine.state.epoch))

        engine.add_event_handler(Events.EPOCH_COMPLETED, print_epoch)

        events_list = Events.EPOCH_COMPLETED | Events.COMPLETED

        def execute_something():
            # do some thing not related to engine
            pass

        engine.add_event_handler(events_list, execute_something)

    Note:
        Since v0.3.0, Events become more flexible and allow to pass an event filter to the Engine.
        See :class:`~ignite.engine.Events` for more details.

    """
    if isinstance(event_name, EventsList):
        for e in event_name:
            self.add_event_handler(e, handler, *args, **kwargs)
        return RemovableEventHandle(event_name, handler, self)
    if (
        isinstance(event_name, CallableEventWithFilter)
        and event_name.filter != CallableEventWithFilter.default_event_filter
    ):
        event_filter = event_name.filter
        handler = self._handler_wrapper(handler, event_name, event_filter)

    if event_name not in self._allowed_events:
        self.logger.error(
            "attempt to add event handler to an invalid event %s.", event_name
        )
        raise ValueError(
            "Event {} is not a valid event for this Engine.".format(event_name)
        )

    event_args = (Exception(),) if event_name == Events.EXCEPTION_RAISED else ()
    try:
        _check_signature(handler, "handler", self, *(event_args + args), **kwargs)
        self._event_handlers[event_name].append((handler, (self,) + args, kwargs))
    except ValueError:
        _check_signature(handler, "handler", *(event_args + args), **kwargs)
        self._event_handlers[event_name].append((handler, args, kwargs))
    self.logger.debug("added handler for event %s.", event_name)

    return RemovableEventHandle(event_name, handler, self)