prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Deprecate ignite.contrib.handlers.custom_events.CustomPeriodicEvent
  ## 🚀 Feature
  
  Custom events `CustomPeriodicEvent` from contrib seem heavy and unusable. 
  
  Idea is to 
  
  - [ ] raise a warning about deprecation since v0.4.0 and removing since v0.5.0 and suggest to use filtered events.
  - [ ] remove all docs about them 
  
  
  </issue>
  <code>
  [start of ignite/contrib/handlers/custom_events.py]
  1 from ignite.engine import Events, State, EventEnum
  2 
  3 
  4 class CustomPeriodicEvent:
  5     """Handler to define a custom periodic events as a number of elapsed iterations/epochs for an engine.
  6 
  7     When custom periodic event is created and attached to an engine, the following events are fired:
  8     1) K iterations is specified:
  9     - `Events.ITERATIONS_<K>_STARTED`
  10     - `Events.ITERATIONS_<K>_COMPLETED`
  11 
  12     1) K epochs is specified:
  13     - `Events.EPOCHS_<K>_STARTED`
  14     - `Events.EPOCHS_<K>_COMPLETED`
  15 
  16 
  17     Examples:
  18 
  19     .. code-block:: python
  20 
  21         from ignite.engine import Engine, Events
  22         from ignite.contrib.handlers import CustomPeriodicEvent
  23 
  24         # Let's define an event every 1000 iterations
  25         cpe1 = CustomPeriodicEvent(n_iterations=1000)
  26         cpe1.attach(trainer)
  27 
  28         # Let's define an event every 10 epochs
  29         cpe2 = CustomPeriodicEvent(n_epochs=10)
  30         cpe2.attach(trainer)
  31 
  32         @trainer.on(cpe1.Events.ITERATIONS_1000_COMPLETED)
  33         def on_every_1000_iterations(engine):
  34             # run a computation after 1000 iterations
  35             # ...
  36             print(engine.state.iterations_1000)
  37 
  38         @trainer.on(cpe2.Events.EPOCHS_10_STARTED)
  39         def on_every_10_epochs(engine):
  40             # run a computation every 10 epochs
  41             # ...
  42             print(engine.state.epochs_10)
  43 
  44 
  45     Args:
  46         n_iterations (int, optional): number iterations of the custom periodic event
  47         n_epochs (int, optional): number iterations of the custom periodic event. Argument is optional, but only one,
  48             either n_iterations or n_epochs should defined.
  49 
  50     """
  51 
  52     def __init__(self, n_iterations=None, n_epochs=None):
  53 
  54         if n_iterations is not None and (not isinstance(n_iterations, int) or n_iterations < 1):
  55             raise ValueError("Argument n_iterations should be positive integer number")
  56 
  57         if n_epochs is not None and (not isinstance(n_epochs, int) or n_epochs < 1):
  58             raise ValueError("Argument n_epochs should be positive integer number")
  59 
  60         if (n_iterations is None and n_epochs is None) or (n_iterations and n_epochs):
  61             raise ValueError("Either n_iterations or n_epochs should defined")
  62 
  63         if n_iterations:
  64             prefix = "iterations"
  65             self.state_attr = "iteration"
  66             self.period = n_iterations
  67 
  68         if n_epochs:
  69             prefix = "epochs"
  70             self.state_attr = "epoch"
  71             self.period = n_epochs
  72 
  73         self.custom_state_attr = "{}_{}".format(prefix, self.period)
  74         event_name = "{}_{}".format(prefix.upper(), self.period)
  75         setattr(
  76             self,
  77             "Events",
  78             EventEnum("Events", " ".join(["{}_STARTED".format(event_name), "{}_COMPLETED".format(event_name)])),
  79         )
  80 
  81         # Update State.event_to_attr
  82         for e in self.Events:
  83             State.event_to_attr[e] = self.custom_state_attr
  84 
  85         # Create aliases
  86         self._periodic_event_started = getattr(self.Events, "{}_STARTED".format(event_name))
  87         self._periodic_event_completed = getattr(self.Events, "{}_COMPLETED".format(event_name))
  88 
  89     def _on_started(self, engine):
  90         setattr(engine.state, self.custom_state_attr, 0)
  91 
  92     def _on_periodic_event_started(self, engine):
  93         if getattr(engine.state, self.state_attr) % self.period == 1:
  94             setattr(engine.state, self.custom_state_attr, getattr(engine.state, self.custom_state_attr) + 1)
  95             engine.fire_event(self._periodic_event_started)
  96 
  97     def _on_periodic_event_completed(self, engine):
  98         if getattr(engine.state, self.state_attr) % self.period == 0:
  99             engine.fire_event(self._periodic_event_completed)
  100 
  101     def attach(self, engine):
  102         engine.register_events(*self.Events)
  103 
  104         engine.add_event_handler(Events.STARTED, self._on_started)
  105         engine.add_event_handler(
  106             getattr(Events, "{}_STARTED".format(self.state_attr.upper())), self._on_periodic_event_started
  107         )
  108         engine.add_event_handler(
  109             getattr(Events, "{}_COMPLETED".format(self.state_attr.upper())), self._on_periodic_event_completed
  110         )
  111
  [end of ignite/contrib/handlers/custom_events.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/ignite/contrib/handlers/custom_events.py b/ignite/contrib/handlers/custom_events.py
  --- a/ignite/contrib/handlers/custom_events.py
  +++ b/ignite/contrib/handlers/custom_events.py
  @@ -1,8 +1,11 @@
   from ignite.engine import Events, State, EventEnum
  +import warnings
   
   
   class CustomPeriodicEvent:
  -    """Handler to define a custom periodic events as a number of elapsed iterations/epochs for an engine.
  +    """DEPRECATED. Use filtered events instead.
  +    Handler to define a custom periodic events as a number of elapsed iterations/epochs
  +    for an engine.
   
       When custom periodic event is created and attached to an engine, the following events are fired:
       1) K iterations is specified:
  @@ -51,6 +54,11 @@
   
       def __init__(self, n_iterations=None, n_epochs=None):
   
  +        warnings.warn(
  +            "CustomPeriodicEvent is deprecated since 0.4.0 and will be removed in 0.5.0. Use filtered events instead.",
  +            DeprecationWarning,
  +        )
  +
           if n_iterations is not None and (not isinstance(n_iterations, int) or n_iterations < 1):
               raise ValueError("Argument n_iterations should be positive integer number")
  
verification_info: {"golden_diff": "diff --git a/ignite/contrib/handlers/custom_events.py b/ignite/contrib/handlers/custom_events.py\n--- a/ignite/contrib/handlers/custom_events.py\n+++ b/ignite/contrib/handlers/custom_events.py\n@@ -1,8 +1,11 @@\n from ignite.engine import Events, State, EventEnum\n+import warnings\n \n \n class CustomPeriodicEvent:\n-    \"\"\"Handler to define a custom periodic events as a number of elapsed iterations/epochs for an engine.\n+    \"\"\"DEPRECATED. Use filtered events instead.\n+    Handler to define a custom periodic events as a number of elapsed iterations/epochs\n+    for an engine.\n \n     When custom periodic event is created and attached to an engine, the following events are fired:\n     1) K iterations is specified:\n@@ -51,6 +54,11 @@\n \n     def __init__(self, n_iterations=None, n_epochs=None):\n \n+        warnings.warn(\n+            \"CustomPeriodicEvent is deprecated since 0.4.0 and will be removed in 0.5.0. Use filtered events instead.\",\n+            DeprecationWarning,\n+        )\n+\n         if n_iterations is not None and (not isinstance(n_iterations, int) or n_iterations < 1):\n             raise ValueError(\"Argument n_iterations should be positive integer number\")\n", "issue": "Deprecate ignite.contrib.handlers.custom_events.CustomPeriodicEvent\n## \ud83d\ude80 Feature\r\n\r\nCustom events `CustomPeriodicEvent` from contrib seem heavy and unusable. \r\n\r\nIdea is to \r\n\r\n- [ ] raise a warning about deprecation since v0.4.0 and removing since v0.5.0 and suggest to use filtered events.\r\n- [ ] remove all docs about them \r\n\n", "before_files": [{"content": "from ignite.engine import Events, State, EventEnum\n\n\nclass CustomPeriodicEvent:\n    \"\"\"Handler to define a custom periodic events as a number of elapsed iterations/epochs for an engine.\n\n    When custom periodic event is created and attached to an engine, the following events are fired:\n    1) K iterations is specified:\n    - `Events.ITERATIONS_<K>_STARTED`\n    - `Events.ITERATIONS_<K>_COMPLETED`\n\n    1) K epochs is specified:\n    - `Events.EPOCHS_<K>_STARTED`\n    - `Events.EPOCHS_<K>_COMPLETED`\n\n\n    Examples:\n\n    .. code-block:: python\n\n        from ignite.engine import Engine, Events\n        from ignite.contrib.handlers import CustomPeriodicEvent\n\n        # Let's define an event every 1000 iterations\n        cpe1 = CustomPeriodicEvent(n_iterations=1000)\n        cpe1.attach(trainer)\n\n        # Let's define an event every 10 epochs\n        cpe2 = CustomPeriodicEvent(n_epochs=10)\n        cpe2.attach(trainer)\n\n        @trainer.on(cpe1.Events.ITERATIONS_1000_COMPLETED)\n        def on_every_1000_iterations(engine):\n            # run a computation after 1000 iterations\n            # ...\n            print(engine.state.iterations_1000)\n\n        @trainer.on(cpe2.Events.EPOCHS_10_STARTED)\n        def on_every_10_epochs(engine):\n            # run a computation every 10 epochs\n            # ...\n            print(engine.state.epochs_10)\n\n\n    Args:\n        n_iterations (int, optional): number iterations of the custom periodic event\n        n_epochs (int, optional): number iterations of the custom periodic event. Argument is optional, but only one,\n            either n_iterations or n_epochs should defined.\n\n    \"\"\"\n\n    def __init__(self, n_iterations=None, n_epochs=None):\n\n        if n_iterations is not None and (not isinstance(n_iterations, int) or n_iterations < 1):\n            raise ValueError(\"Argument n_iterations should be positive integer number\")\n\n        if n_epochs is not None and (not isinstance(n_epochs, int) or n_epochs < 1):\n            raise ValueError(\"Argument n_epochs should be positive integer number\")\n\n        if (n_iterations is None and n_epochs is None) or (n_iterations and n_epochs):\n            raise ValueError(\"Either n_iterations or n_epochs should defined\")\n\n        if n_iterations:\n            prefix = \"iterations\"\n            self.state_attr = \"iteration\"\n            self.period = n_iterations\n\n        if n_epochs:\n            prefix = \"epochs\"\n            self.state_attr = \"epoch\"\n            self.period = n_epochs\n\n        self.custom_state_attr = \"{}_{}\".format(prefix, self.period)\n        event_name = \"{}_{}\".format(prefix.upper(), self.period)\n        setattr(\n            self,\n            \"Events\",\n            EventEnum(\"Events\", \" \".join([\"{}_STARTED\".format(event_name), \"{}_COMPLETED\".format(event_name)])),\n        )\n\n        # Update State.event_to_attr\n        for e in self.Events:\n            State.event_to_attr[e] = self.custom_state_attr\n\n        # Create aliases\n        self._periodic_event_started = getattr(self.Events, \"{}_STARTED\".format(event_name))\n        self._periodic_event_completed = getattr(self.Events, \"{}_COMPLETED\".format(event_name))\n\n    def _on_started(self, engine):\n        setattr(engine.state, self.custom_state_attr, 0)\n\n    def _on_periodic_event_started(self, engine):\n        if getattr(engine.state, self.state_attr) % self.period == 1:\n            setattr(engine.state, self.custom_state_attr, getattr(engine.state, self.custom_state_attr) + 1)\n            engine.fire_event(self._periodic_event_started)\n\n    def _on_periodic_event_completed(self, engine):\n        if getattr(engine.state, self.state_attr) % self.period == 0:\n            engine.fire_event(self._periodic_event_completed)\n\n    def attach(self, engine):\n        engine.register_events(*self.Events)\n\n        engine.add_event_handler(Events.STARTED, self._on_started)\n        engine.add_event_handler(\n            getattr(Events, \"{}_STARTED\".format(self.state_attr.upper())), self._on_periodic_event_started\n        )\n        engine.add_event_handler(\n            getattr(Events, \"{}_COMPLETED\".format(self.state_attr.upper())), self._on_periodic_event_completed\n        )\n", "path": "ignite/contrib/handlers/custom_events.py"}]}