We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Bug adding handler in case of decoration + class function + filtered event
## 🐛 Bug description

I would like to report a bug using handler defined by decorated function in a class with filtered event.

The following code reproduces all possible situations to add an handler defined w/wo decoration in a class or not, w/wo engine (or args), using an event w/wo filter

```python
engine = Engine(lambda e, b: b)

# decorator
def decorated(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        return fun(*args, **kwargs)
    return wrapper

# handler as a function
def foo():
    print("foo")

# handler as a decorated function
@decorated
def decorated_foo():
    print("decorated_foo")

# register handler as a function -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo)
# register handler as a function with filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo)
# register handler as a decorated function -- OK
engine.add_event_handler(Events.EPOCH_STARTED, decorated_foo)
# register handler as a decorated function with filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), decorated_foo)


# handler as a function with engine (here args)
def foo_args(args):
    print("foo_args", args)


# handler as a decorated function with engine 
@decorated
def decorated_foo_args(args):
    print("decorated_foo_args", args)

# register handler as a function with engine  -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo_args)
# register handler as a function with engine and filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo_args)
# register handler as a decorated function with engine -- OK
engine.add_event_handler(Events.EPOCH_STARTED, decorated_foo_args)
# register handler as a decorated function with engine and filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), decorated_foo_args)

class Foo:
    # handler as a class function (ie method)
    def foo(self):
        print("foo")

    # handler as a decorated method
    @decorated
    def decorated_foo(self):
        print("decorated_foo")

    # handler as a method with engine
    def foo_args(self, args):
        print("foo_args", args)

    # handler as a decorated method with engine
    @decorated
    def decorated_foo_args(self, args):
        print("decorated_foo_args", args)


foo = Foo()

# register handler as a method -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo.foo)
# register handler as a method with filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.foo)
# register handler as a decorated method -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo.decorated_foo)
# register handler as a decorated method with filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.decorated_foo)
# register handler as a method with engine  -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo.foo_args)
# register handler as a method with engine and filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.foo_args)
# register handler as a decorated method with engine -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo.decorated_foo_args)

# register handler as a decorated method with engine and filter -- FAILED
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.decorated_foo_args)

engine.run([0])
```

The error is
```
Error adding <function Foo.decorated_foo_args at 0x1229b6af0> 'handler': takes parameters ['self', 'args'] but will be called with [](missing a required argument: 'self').
```

Why ? 

First, a handler defined with a filtered event is wrapped with decoration. See https://github.com/sdesrozis/ignite/blob/93be57aa3f71ce601391d59096c3b430c4d9487b/ignite/engine/engine.py#L198. Note that `functools.wraps` is used to fit the signature of the related handler.

The failed case is decorated method with engine. So, I guess `functools.wraps` works perfectly and catch `self` and `engine` as arguments. But the signature checking search (using `inspect.signature`) fails because missing `self`... 

See signature checking
https://github.com/pytorch/ignite/blob/0de7156bb284bd01d788252469a3b386f10abbd7/ignite/engine/utils.py#L5

I think this is related to `follow_wrapped=True` argument of `inspect.signature`.

## Environment

 - PyTorch Version (e.g., 1.4): 1.5
 - Ignite Version (e.g., 0.3.0): 0.4
 - OS (e.g., Linux): MacOS
 - How you installed Ignite (`conda`, `pip`, source): Honda
 - Python version: 3.7
 - Any other relevant information:


Bug adding handler in case of decoration + class function + filtered event
## 🐛 Bug description

I would like to report a bug using handler defined by decorated function in a class with filtered event.

The following code reproduces all possible situations to add an handler defined w/wo decoration in a class or not, w/wo engine (or args), using an event w/wo filter

```python
engine = Engine(lambda e, b: b)

# decorator
def decorated(fun):
    @functools.wraps(fun)
    def wrapper(*args, **kwargs):
        return fun(*args, **kwargs)
    return wrapper

# handler as a function
def foo():
    print("foo")

# handler as a decorated function
@decorated
def decorated_foo():
    print("decorated_foo")

# register handler as a function -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo)
# register handler as a function with filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo)
# register handler as a decorated function -- OK
engine.add_event_handler(Events.EPOCH_STARTED, decorated_foo)
# register handler as a decorated function with filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), decorated_foo)


# handler as a function with engine (here args)
def foo_args(args):
    print("foo_args", args)


# handler as a decorated function with engine 
@decorated
def decorated_foo_args(args):
    print("decorated_foo_args", args)

# register handler as a function with engine  -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo_args)
# register handler as a function with engine and filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo_args)
# register handler as a decorated function with engine -- OK
engine.add_event_handler(Events.EPOCH_STARTED, decorated_foo_args)
# register handler as a decorated function with engine and filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), decorated_foo_args)

class Foo:
    # handler as a class function (ie method)
    def foo(self):
        print("foo")

    # handler as a decorated method
    @decorated
    def decorated_foo(self):
        print("decorated_foo")

    # handler as a method with engine
    def foo_args(self, args):
        print("foo_args", args)

    # handler as a decorated method with engine
    @decorated
    def decorated_foo_args(self, args):
        print("decorated_foo_args", args)


foo = Foo()

# register handler as a method -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo.foo)
# register handler as a method with filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.foo)
# register handler as a decorated method -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo.decorated_foo)
# register handler as a decorated method with filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.decorated_foo)
# register handler as a method with engine  -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo.foo_args)
# register handler as a method with engine and filter -- OK
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.foo_args)
# register handler as a decorated method with engine -- OK
engine.add_event_handler(Events.EPOCH_STARTED, foo.decorated_foo_args)

# register handler as a decorated method with engine and filter -- FAILED
engine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.decorated_foo_args)

engine.run([0])
```

The error is
```
Error adding <function Foo.decorated_foo_args at 0x1229b6af0> 'handler': takes parameters ['self', 'args'] but will be called with [](missing a required argument: 'self').
```

Why ? 

First, a handler defined with a filtered event is wrapped with decoration. See https://github.com/sdesrozis/ignite/blob/93be57aa3f71ce601391d59096c3b430c4d9487b/ignite/engine/engine.py#L198. Note that `functools.wraps` is used to fit the signature of the related handler.

The failed case is decorated method with engine. So, I guess `functools.wraps` works perfectly and catch `self` and `engine` as arguments. But the signature checking search (using `inspect.signature`) fails because missing `self`... 

See signature checking
https://github.com/pytorch/ignite/blob/0de7156bb284bd01d788252469a3b386f10abbd7/ignite/engine/utils.py#L5

I think this is related to `follow_wrapped=True` argument of `inspect.signature`.

## Environment

 - PyTorch Version (e.g., 1.4): 1.5
 - Ignite Version (e.g., 0.3.0): 0.4
 - OS (e.g., Linux): MacOS
 - How you installed Ignite (`conda`, `pip`, source): Honda
 - Python version: 3.7
 - Any other relevant information:



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ignite/engine/utils.py`
Content:
```
1 import inspect
2 from typing import Callable
3 
4 
5 def _check_signature(fn: Callable, fn_description: str, *args, **kwargs) -> None:
6     signature = inspect.signature(fn)
7     try:  # try without engine
8         signature.bind(*args, **kwargs)
9     except TypeError as exc:
10         fn_params = list(signature.parameters)
11         exception_msg = str(exc)
12         passed_params = list(args) + list(kwargs)
13         raise ValueError(
14             "Error adding {} '{}': "
15             "takes parameters {} but will be called with {}"
16             "({}).".format(fn, fn_description, fn_params, passed_params, exception_msg)
17         )
18
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ignite/engine/utils.py b/ignite/engine/utils.py
--- a/ignite/engine/utils.py
+++ b/ignite/engine/utils.py
@@ -3,7 +3,11 @@
 
 
 def _check_signature(fn: Callable, fn_description: str, *args, **kwargs) -> None:
-    signature = inspect.signature(fn)
+    # if handler with filter, check the handler rather than the decorator
+    if hasattr(fn, "_parent"):
+        signature = inspect.signature(fn._parent())
+    else:
+        signature = inspect.signature(fn)
     try:  # try without engine
         signature.bind(*args, **kwargs)
     except TypeError as exc:

{"golden_diff": "diff --git a/ignite/engine/utils.py b/ignite/engine/utils.py\n--- a/ignite/engine/utils.py\n+++ b/ignite/engine/utils.py\n@@ -3,7 +3,11 @@\n \n \n def _check_signature(fn: Callable, fn_description: str, *args, **kwargs) -> None:\n-    signature = inspect.signature(fn)\n+    # if handler with filter, check the handler rather than the decorator\n+    if hasattr(fn, \"_parent\"):\n+        signature = inspect.signature(fn._parent())\n+    else:\n+        signature = inspect.signature(fn)\n     try:  # try without engine\n         signature.bind(*args, **kwargs)\n     except TypeError as exc:\n", "issue": "Bug adding handler in case of decoration + class function + filtered event\n## \ud83d\udc1b Bug description\r\n\r\nI would like to report a bug using handler defined by decorated function in a class with filtered event.\r\n\r\nThe following code reproduces all possible situations to add an handler defined w/wo decoration in a class or not, w/wo engine (or args), using an event w/wo filter\r\n\r\n```python\r\nengine = Engine(lambda e, b: b)\r\n\r\n# decorator\r\ndef decorated(fun):\r\n    @functools.wraps(fun)\r\n    def wrapper(*args, **kwargs):\r\n        return fun(*args, **kwargs)\r\n    return wrapper\r\n\r\n# handler as a function\r\ndef foo():\r\n    print(\"foo\")\r\n\r\n# handler as a decorated function\r\n@decorated\r\ndef decorated_foo():\r\n    print(\"decorated_foo\")\r\n\r\n# register handler as a function -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo)\r\n# register handler as a function with filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo)\r\n# register handler as a decorated function -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, decorated_foo)\r\n# register handler as a decorated function with filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), decorated_foo)\r\n\r\n\r\n# handler as a function with engine (here args)\r\ndef foo_args(args):\r\n    print(\"foo_args\", args)\r\n\r\n\r\n# handler as a decorated function with engine \r\n@decorated\r\ndef decorated_foo_args(args):\r\n    print(\"decorated_foo_args\", args)\r\n\r\n# register handler as a function with engine  -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo_args)\r\n# register handler as a function with engine and filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo_args)\r\n# register handler as a decorated function with engine -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, decorated_foo_args)\r\n# register handler as a decorated function with engine and filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), decorated_foo_args)\r\n\r\nclass Foo:\r\n    # handler as a class function (ie method)\r\n    def foo(self):\r\n        print(\"foo\")\r\n\r\n    # handler as a decorated method\r\n    @decorated\r\n    def decorated_foo(self):\r\n        print(\"decorated_foo\")\r\n\r\n    # handler as a method with engine\r\n    def foo_args(self, args):\r\n        print(\"foo_args\", args)\r\n\r\n    # handler as a decorated method with engine\r\n    @decorated\r\n    def decorated_foo_args(self, args):\r\n        print(\"decorated_foo_args\", args)\r\n\r\n\r\nfoo = Foo()\r\n\r\n# register handler as a method -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo.foo)\r\n# register handler as a method with filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.foo)\r\n# register handler as a decorated method -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo.decorated_foo)\r\n# register handler as a decorated method with filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.decorated_foo)\r\n# register handler as a method with engine  -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo.foo_args)\r\n# register handler as a method with engine and filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.foo_args)\r\n# register handler as a decorated method with engine -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo.decorated_foo_args)\r\n\r\n# register handler as a decorated method with engine and filter -- FAILED\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.decorated_foo_args)\r\n\r\nengine.run([0])\r\n```\r\n\r\nThe error is\r\n```\r\nError adding <function Foo.decorated_foo_args at 0x1229b6af0> 'handler': takes parameters ['self', 'args'] but will be called with [](missing a required argument: 'self').\r\n```\r\n\r\nWhy ? \r\n\r\nFirst, a handler defined with a filtered event is wrapped with decoration. See https://github.com/sdesrozis/ignite/blob/93be57aa3f71ce601391d59096c3b430c4d9487b/ignite/engine/engine.py#L198. Note that `functools.wraps` is used to fit the signature of the related handler.\r\n\r\nThe failed case is decorated method with engine. So, I guess `functools.wraps` works perfectly and catch `self` and `engine` as arguments. But the signature checking search (using `inspect.signature`) fails because missing `self`... \r\n\r\nSee signature checking\r\nhttps://github.com/pytorch/ignite/blob/0de7156bb284bd01d788252469a3b386f10abbd7/ignite/engine/utils.py#L5\r\n\r\nI think this is related to `follow_wrapped=True` argument of `inspect.signature`.\r\n\r\n## Environment\r\n\r\n - PyTorch Version (e.g., 1.4): 1.5\r\n - Ignite Version (e.g., 0.3.0): 0.4\r\n - OS (e.g., Linux): MacOS\r\n - How you installed Ignite (`conda`, `pip`, source): Honda\r\n - Python version: 3.7\r\n - Any other relevant information:\r\n\r\n\nBug adding handler in case of decoration + class function + filtered event\n## \ud83d\udc1b Bug description\r\n\r\nI would like to report a bug using handler defined by decorated function in a class with filtered event.\r\n\r\nThe following code reproduces all possible situations to add an handler defined w/wo decoration in a class or not, w/wo engine (or args), using an event w/wo filter\r\n\r\n```python\r\nengine = Engine(lambda e, b: b)\r\n\r\n# decorator\r\ndef decorated(fun):\r\n    @functools.wraps(fun)\r\n    def wrapper(*args, **kwargs):\r\n        return fun(*args, **kwargs)\r\n    return wrapper\r\n\r\n# handler as a function\r\ndef foo():\r\n    print(\"foo\")\r\n\r\n# handler as a decorated function\r\n@decorated\r\ndef decorated_foo():\r\n    print(\"decorated_foo\")\r\n\r\n# register handler as a function -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo)\r\n# register handler as a function with filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo)\r\n# register handler as a decorated function -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, decorated_foo)\r\n# register handler as a decorated function with filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), decorated_foo)\r\n\r\n\r\n# handler as a function with engine (here args)\r\ndef foo_args(args):\r\n    print(\"foo_args\", args)\r\n\r\n\r\n# handler as a decorated function with engine \r\n@decorated\r\ndef decorated_foo_args(args):\r\n    print(\"decorated_foo_args\", args)\r\n\r\n# register handler as a function with engine  -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo_args)\r\n# register handler as a function with engine and filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo_args)\r\n# register handler as a decorated function with engine -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, decorated_foo_args)\r\n# register handler as a decorated function with engine and filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), decorated_foo_args)\r\n\r\nclass Foo:\r\n    # handler as a class function (ie method)\r\n    def foo(self):\r\n        print(\"foo\")\r\n\r\n    # handler as a decorated method\r\n    @decorated\r\n    def decorated_foo(self):\r\n        print(\"decorated_foo\")\r\n\r\n    # handler as a method with engine\r\n    def foo_args(self, args):\r\n        print(\"foo_args\", args)\r\n\r\n    # handler as a decorated method with engine\r\n    @decorated\r\n    def decorated_foo_args(self, args):\r\n        print(\"decorated_foo_args\", args)\r\n\r\n\r\nfoo = Foo()\r\n\r\n# register handler as a method -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo.foo)\r\n# register handler as a method with filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.foo)\r\n# register handler as a decorated method -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo.decorated_foo)\r\n# register handler as a decorated method with filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.decorated_foo)\r\n# register handler as a method with engine  -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo.foo_args)\r\n# register handler as a method with engine and filter -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.foo_args)\r\n# register handler as a decorated method with engine -- OK\r\nengine.add_event_handler(Events.EPOCH_STARTED, foo.decorated_foo_args)\r\n\r\n# register handler as a decorated method with engine and filter -- FAILED\r\nengine.add_event_handler(Events.EPOCH_STARTED(every=2), foo.decorated_foo_args)\r\n\r\nengine.run([0])\r\n```\r\n\r\nThe error is\r\n```\r\nError adding <function Foo.decorated_foo_args at 0x1229b6af0> 'handler': takes parameters ['self', 'args'] but will be called with [](missing a required argument: 'self').\r\n```\r\n\r\nWhy ? \r\n\r\nFirst, a handler defined with a filtered event is wrapped with decoration. See https://github.com/sdesrozis/ignite/blob/93be57aa3f71ce601391d59096c3b430c4d9487b/ignite/engine/engine.py#L198. Note that `functools.wraps` is used to fit the signature of the related handler.\r\n\r\nThe failed case is decorated method with engine. So, I guess `functools.wraps` works perfectly and catch `self` and `engine` as arguments. But the signature checking search (using `inspect.signature`) fails because missing `self`... \r\n\r\nSee signature checking\r\nhttps://github.com/pytorch/ignite/blob/0de7156bb284bd01d788252469a3b386f10abbd7/ignite/engine/utils.py#L5\r\n\r\nI think this is related to `follow_wrapped=True` argument of `inspect.signature`.\r\n\r\n## Environment\r\n\r\n - PyTorch Version (e.g., 1.4): 1.5\r\n - Ignite Version (e.g., 0.3.0): 0.4\r\n - OS (e.g., Linux): MacOS\r\n - How you installed Ignite (`conda`, `pip`, source): Honda\r\n - Python version: 3.7\r\n - Any other relevant information:\r\n\r\n\n", "before_files": [{"content": "import inspect\nfrom typing import Callable\n\n\ndef _check_signature(fn: Callable, fn_description: str, *args, **kwargs) -> None:\n    signature = inspect.signature(fn)\n    try:  # try without engine\n        signature.bind(*args, **kwargs)\n    except TypeError as exc:\n        fn_params = list(signature.parameters)\n        exception_msg = str(exc)\n        passed_params = list(args) + list(kwargs)\n        raise ValueError(\n            \"Error adding {} '{}': \"\n            \"takes parameters {} but will be called with {}\"\n            \"({}).\".format(fn, fn_description, fn_params, passed_params, exception_msg)\n        )\n", "path": "ignite/engine/utils.py"}], "after_files": [{"content": "import inspect\nfrom typing import Callable\n\n\ndef _check_signature(fn: Callable, fn_description: str, *args, **kwargs) -> None:\n    # if handler with filter, check the handler rather than the decorator\n    if hasattr(fn, \"_parent\"):\n        signature = inspect.signature(fn._parent())\n    else:\n        signature = inspect.signature(fn)\n    try:  # try without engine\n        signature.bind(*args, **kwargs)\n    except TypeError as exc:\n        fn_params = list(signature.parameters)\n        exception_msg = str(exc)\n        passed_params = list(args) + list(kwargs)\n        raise ValueError(\n            \"Error adding {} '{}': \"\n            \"takes parameters {} but will be called with {}\"\n            \"({}).\".format(fn, fn_description, fn_params, passed_params, exception_msg)\n        )\n", "path": "ignite/engine/utils.py"}]}