We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
walltime app function parameter modifies task_record func_name
**Describe the bug**
When the walltime special parameter is passed to a Parsl app the `task_record['func_name']` parameter is set to "wrapper" instead of to the function's name. 

**To Reproduce**
Launch the code below using parsl version 1.2.0:
```
import parsl
print(parsl.__version__, flush = True)
from parsl.app.app import python_app, bash_app
from parsl.config import Config
from parsl.executors import HighThroughputExecutor


@python_app
def test(stdout='std.out', stderr = 'std.err', walltime = 5):
    from time import sleep
    sleep(1)
    Fail = 1/0
    return 'Hello'

def retry_handler(exception, task_record):
    print(task_record['func_name'], flush = True)
    return 1

if __name__ == '__main__':

    config = Config(
        executors = [HighThroughputExecutor()],
        retries = 2,
        retry_handler = retry_handler
    )
    print('Loading Parsl Config', flush = True)
    parsl.load(config)

    fut = test()

    print(fut.result())

```

It will print "wrapper" if the walltime parameter is present and test otherwise. 

**Expected behavior**
The code should print the function's name (test).

**Environment**
- OS: Linux
- Python version: 3.10.4
- Parsl version: 1.2.0


**Distributed Environment**
- Where are you running the Parsl script from ? Local
- Where do you need the workers to run ? Local


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `parsl/app/python.py`
Content:
```
1 import logging
2 
3 import tblib.pickling_support
4 tblib.pickling_support.install()
5 
6 from parsl.app.app import AppBase
7 from parsl.app.errors import wrap_error
8 from parsl.dataflow.dflow import DataFlowKernelLoader
9 
10 
11 logger = logging.getLogger(__name__)
12 
13 
14 def timeout(f, seconds):
15     def wrapper(*args, **kwargs):
16         import threading
17         import ctypes
18         import parsl.app.errors
19 
20         def inject_exception(thread):
21             ctypes.pythonapi.PyThreadState_SetAsyncExc(
22                 ctypes.c_long(thread),
23                 ctypes.py_object(parsl.app.errors.AppTimeout)
24             )
25 
26         thread = threading.current_thread().ident
27         timer = threading.Timer(seconds, inject_exception, args=[thread])
28         timer.start()
29         result = f(*args, **kwargs)
30         timer.cancel()
31         return result
32     return wrapper
33 
34 
35 class PythonApp(AppBase):
36     """Extends AppBase to cover the Python App."""
37 
38     def __init__(self, func, data_flow_kernel=None, cache=False, executors='all', ignore_for_cache=[], join=False):
39         super().__init__(
40             wrap_error(func),
41             data_flow_kernel=data_flow_kernel,
42             executors=executors,
43             cache=cache,
44             ignore_for_cache=ignore_for_cache
45         )
46         self.join = join
47 
48     def __call__(self, *args, **kwargs):
49         """This is where the call to a python app is handled.
50 
51         Args:
52              - Arbitrary
53         Kwargs:
54              - Arbitrary
55 
56         Returns:
57                    App_fut
58 
59         """
60         invocation_kwargs = {}
61         invocation_kwargs.update(self.kwargs)
62         invocation_kwargs.update(kwargs)
63 
64         if self.data_flow_kernel is None:
65             dfk = DataFlowKernelLoader.dfk()
66         else:
67             dfk = self.data_flow_kernel
68 
69         walltime = invocation_kwargs.get('walltime')
70         if walltime is not None:
71             func = timeout(self.func, walltime)
72         else:
73             func = self.func
74 
75         app_fut = dfk.submit(func, app_args=args,
76                              executors=self.executors,
77                              cache=self.cache,
78                              ignore_for_cache=self.ignore_for_cache,
79                              app_kwargs=invocation_kwargs,
80                              join=self.join)
81 
82         return app_fut
83
```
--- 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/parsl/app/python.py b/parsl/app/python.py
--- a/parsl/app/python.py
+++ b/parsl/app/python.py
@@ -3,6 +3,8 @@
 import tblib.pickling_support
 tblib.pickling_support.install()
 
+from functools import wraps
+
 from parsl.app.app import AppBase
 from parsl.app.errors import wrap_error
 from parsl.dataflow.dflow import DataFlowKernelLoader
@@ -12,6 +14,7 @@
 
 
 def timeout(f, seconds):
+    @wraps(f)
     def wrapper(*args, **kwargs):
         import threading
         import ctypes

{"golden_diff": "diff --git a/parsl/app/python.py b/parsl/app/python.py\n--- a/parsl/app/python.py\n+++ b/parsl/app/python.py\n@@ -3,6 +3,8 @@\n import tblib.pickling_support\n tblib.pickling_support.install()\n \n+from functools import wraps\n+\n from parsl.app.app import AppBase\n from parsl.app.errors import wrap_error\n from parsl.dataflow.dflow import DataFlowKernelLoader\n@@ -12,6 +14,7 @@\n \n \n def timeout(f, seconds):\n+    @wraps(f)\n     def wrapper(*args, **kwargs):\n         import threading\n         import ctypes\n", "issue": "walltime app function parameter modifies task_record func_name\n**Describe the bug**\r\nWhen the walltime special parameter is passed to a Parsl app the `task_record['func_name']` parameter is set to \"wrapper\" instead of to the function's name. \r\n\r\n**To Reproduce**\r\nLaunch the code below using parsl version 1.2.0:\r\n```\r\nimport parsl\r\nprint(parsl.__version__, flush = True)\r\nfrom parsl.app.app import python_app, bash_app\r\nfrom parsl.config import Config\r\nfrom parsl.executors import HighThroughputExecutor\r\n\r\n\r\n@python_app\r\ndef test(stdout='std.out', stderr = 'std.err', walltime = 5):\r\n    from time import sleep\r\n    sleep(1)\r\n    Fail = 1/0\r\n    return 'Hello'\r\n\r\ndef retry_handler(exception, task_record):\r\n    print(task_record['func_name'], flush = True)\r\n    return 1\r\n\r\nif __name__ == '__main__':\r\n\r\n    config = Config(\r\n        executors = [HighThroughputExecutor()],\r\n        retries = 2,\r\n        retry_handler = retry_handler\r\n    )\r\n    print('Loading Parsl Config', flush = True)\r\n    parsl.load(config)\r\n\r\n    fut = test()\r\n\r\n    print(fut.result())\r\n\r\n```\r\n\r\nIt will print \"wrapper\" if the walltime parameter is present and test otherwise. \r\n\r\n**Expected behavior**\r\nThe code should print the function's name (test).\r\n\r\n**Environment**\r\n- OS: Linux\r\n- Python version: 3.10.4\r\n- Parsl version: 1.2.0\r\n\r\n\r\n**Distributed Environment**\r\n- Where are you running the Parsl script from ? Local\r\n- Where do you need the workers to run ? Local\r\n\n", "before_files": [{"content": "import logging\n\nimport tblib.pickling_support\ntblib.pickling_support.install()\n\nfrom parsl.app.app import AppBase\nfrom parsl.app.errors import wrap_error\nfrom parsl.dataflow.dflow import DataFlowKernelLoader\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef timeout(f, seconds):\n    def wrapper(*args, **kwargs):\n        import threading\n        import ctypes\n        import parsl.app.errors\n\n        def inject_exception(thread):\n            ctypes.pythonapi.PyThreadState_SetAsyncExc(\n                ctypes.c_long(thread),\n                ctypes.py_object(parsl.app.errors.AppTimeout)\n            )\n\n        thread = threading.current_thread().ident\n        timer = threading.Timer(seconds, inject_exception, args=[thread])\n        timer.start()\n        result = f(*args, **kwargs)\n        timer.cancel()\n        return result\n    return wrapper\n\n\nclass PythonApp(AppBase):\n    \"\"\"Extends AppBase to cover the Python App.\"\"\"\n\n    def __init__(self, func, data_flow_kernel=None, cache=False, executors='all', ignore_for_cache=[], join=False):\n        super().__init__(\n            wrap_error(func),\n            data_flow_kernel=data_flow_kernel,\n            executors=executors,\n            cache=cache,\n            ignore_for_cache=ignore_for_cache\n        )\n        self.join = join\n\n    def __call__(self, *args, **kwargs):\n        \"\"\"This is where the call to a python app is handled.\n\n        Args:\n             - Arbitrary\n        Kwargs:\n             - Arbitrary\n\n        Returns:\n                   App_fut\n\n        \"\"\"\n        invocation_kwargs = {}\n        invocation_kwargs.update(self.kwargs)\n        invocation_kwargs.update(kwargs)\n\n        if self.data_flow_kernel is None:\n            dfk = DataFlowKernelLoader.dfk()\n        else:\n            dfk = self.data_flow_kernel\n\n        walltime = invocation_kwargs.get('walltime')\n        if walltime is not None:\n            func = timeout(self.func, walltime)\n        else:\n            func = self.func\n\n        app_fut = dfk.submit(func, app_args=args,\n                             executors=self.executors,\n                             cache=self.cache,\n                             ignore_for_cache=self.ignore_for_cache,\n                             app_kwargs=invocation_kwargs,\n                             join=self.join)\n\n        return app_fut\n", "path": "parsl/app/python.py"}], "after_files": [{"content": "import logging\n\nimport tblib.pickling_support\ntblib.pickling_support.install()\n\nfrom functools import wraps\n\nfrom parsl.app.app import AppBase\nfrom parsl.app.errors import wrap_error\nfrom parsl.dataflow.dflow import DataFlowKernelLoader\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef timeout(f, seconds):\n    @wraps(f)\n    def wrapper(*args, **kwargs):\n        import threading\n        import ctypes\n        import parsl.app.errors\n\n        def inject_exception(thread):\n            ctypes.pythonapi.PyThreadState_SetAsyncExc(\n                ctypes.c_long(thread),\n                ctypes.py_object(parsl.app.errors.AppTimeout)\n            )\n\n        thread = threading.current_thread().ident\n        timer = threading.Timer(seconds, inject_exception, args=[thread])\n        timer.start()\n        result = f(*args, **kwargs)\n        timer.cancel()\n        return result\n    return wrapper\n\n\nclass PythonApp(AppBase):\n    \"\"\"Extends AppBase to cover the Python App.\"\"\"\n\n    def __init__(self, func, data_flow_kernel=None, cache=False, executors='all', ignore_for_cache=[], join=False):\n        super().__init__(\n            wrap_error(func),\n            data_flow_kernel=data_flow_kernel,\n            executors=executors,\n            cache=cache,\n            ignore_for_cache=ignore_for_cache\n        )\n        self.join = join\n\n    def __call__(self, *args, **kwargs):\n        \"\"\"This is where the call to a python app is handled.\n\n        Args:\n             - Arbitrary\n        Kwargs:\n             - Arbitrary\n\n        Returns:\n                   App_fut\n\n        \"\"\"\n        invocation_kwargs = {}\n        invocation_kwargs.update(self.kwargs)\n        invocation_kwargs.update(kwargs)\n\n        if self.data_flow_kernel is None:\n            dfk = DataFlowKernelLoader.dfk()\n        else:\n            dfk = self.data_flow_kernel\n\n        walltime = invocation_kwargs.get('walltime')\n        if walltime is not None:\n            func = timeout(self.func, walltime)\n        else:\n            func = self.func\n\n        app_fut = dfk.submit(func, app_args=args,\n                             executors=self.executors,\n                             cache=self.cache,\n                             ignore_for_cache=self.ignore_for_cache,\n                             app_kwargs=invocation_kwargs,\n                             join=self.join)\n\n        return app_fut\n", "path": "parsl/app/python.py"}]}