prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Properly handle func names for bash apps
  At the moment bash apps are always `remote_side_bash_executor` in the monitoring DB because that is what is actually running. We should pass through the name of the app's function instead.
  
  --- 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/bash.py`
  Content:
  ```
  1 import logging
  2 
  3 from inspect import signature, Parameter
  4 from parsl.app.errors import wrap_error
  5 from parsl.app.futures import DataFuture
  6 from parsl.app.app import AppBase
  7 from parsl.dataflow.dflow import DataFlowKernelLoader
  8 
  9 logger = logging.getLogger(__name__)
  10 
  11 
  12 def remote_side_bash_executor(func, *args, **kwargs):
  13     """Execute the bash app type function and return the command line string.
  14 
  15     This string is reformatted with the *args, and **kwargs
  16     from call time.
  17     """
  18     import os
  19     import time
  20     import subprocess
  21     import logging
  22     import parsl.app.errors as pe
  23 
  24     logging.basicConfig(filename='/tmp/bashexec.{0}.log'.format(time.time()), level=logging.DEBUG)
  25 
  26     # start_t = time.time()
  27 
  28     func_name = func.__name__
  29 
  30     partial_cmdline = None
  31 
  32     # Try to run the func to compose the commandline
  33     try:
  34         # Execute the func to get the commandline
  35         partial_cmdline = func(*args, **kwargs)
  36         # Reformat the commandline with current args and kwargs
  37         executable = partial_cmdline.format(*args, **kwargs)
  38 
  39     except AttributeError as e:
  40         if partial_cmdline is not None:
  41             raise pe.AppBadFormatting("App formatting failed for app '{}' with AttributeError: {}".format(func_name, e))
  42         else:
  43             raise pe.BashAppNoReturn("Bash app '{}' did not return a value, or returned none - with this exception: {}".format(func_name, e), None)
  44 
  45     except IndexError as e:
  46         raise pe.AppBadFormatting("App formatting failed for app '{}' with IndexError: {}".format(func_name, e))
  47     except Exception as e:
  48         logging.error("Caught exception during formatting of app '{}': {}".format(func_name, e))
  49         raise e
  50 
  51     logging.debug("Executable: %s", executable)
  52 
  53     # Updating stdout, stderr if values passed at call time.
  54 
  55     def open_std_fd(fdname):
  56         # fdname is 'stdout' or 'stderr'
  57         stdfspec = kwargs.get(fdname)  # spec is str name or tuple (name, mode)
  58         if stdfspec is None:
  59             return None
  60         elif isinstance(stdfspec, str):
  61             fname = stdfspec
  62             mode = 'a+'
  63         elif isinstance(stdfspec, tuple):
  64             if len(stdfspec) != 2:
  65                 raise pe.BadStdStreamFile("std descriptor %s has incorrect tuple length %s" % (fdname, len(stdfspec)), TypeError('Bad Tuple Length'))
  66             fname, mode = stdfspec
  67         else:
  68             raise pe.BadStdStreamFile("std descriptor %s has unexpected type %s" % (fdname, str(type(stdfspec))), TypeError('Bad Tuple Type'))
  69         try:
  70             fd = open(fname, mode)
  71         except Exception as e:
  72             raise pe.BadStdStreamFile(fname, e)
  73         return fd
  74 
  75     std_out = open_std_fd('stdout')
  76     std_err = open_std_fd('stderr')
  77     timeout = kwargs.get('walltime')
  78 
  79     returncode = None
  80     try:
  81         proc = subprocess.Popen(executable, stdout=std_out, stderr=std_err, shell=True, executable='/bin/bash')
  82         proc.wait(timeout=timeout)
  83         returncode = proc.returncode
  84 
  85     except subprocess.TimeoutExpired:
  86         # print("Timeout")
  87         raise pe.AppTimeout("[{}] App exceeded walltime: {}".format(func_name, timeout))
  88 
  89     except Exception as e:
  90         # print("Caught exception: ", e)
  91         raise pe.AppException("[{}] App caught exception: {}".format(func_name, proc.returncode), e)
  92 
  93     if returncode != 0:
  94         raise pe.AppFailure("[{}] App failed with exit code: {}".format(func_name, proc.returncode), proc.returncode)
  95 
  96     # TODO : Add support for globs here
  97 
  98     missing = []
  99     for outputfile in kwargs.get('outputs', []):
  100         fpath = outputfile
  101         if type(outputfile) != str:
  102             fpath = outputfile.filepath
  103 
  104         if not os.path.exists(fpath):
  105             missing.extend([outputfile])
  106 
  107     if missing:
  108         raise pe.MissingOutputs("[{}] Missing outputs".format(func_name), missing)
  109 
  110     # exec_duration = time.time() - start_t
  111     return returncode
  112 
  113 
  114 class BashApp(AppBase):
  115 
  116     def __init__(self, func, data_flow_kernel=None, walltime=60, cache=False, executors='all'):
  117         super().__init__(func, data_flow_kernel=data_flow_kernel, walltime=60, executors=executors, cache=cache)
  118         self.kwargs = {}
  119 
  120         # We duplicate the extraction of parameter defaults
  121         # to self.kwargs to ensure availability at point of
  122         # command string format. Refer: #349
  123         sig = signature(func)
  124 
  125         for s in sig.parameters:
  126             if sig.parameters[s].default != Parameter.empty:
  127                 self.kwargs[s] = sig.parameters[s].default
  128 
  129     def __call__(self, *args, **kwargs):
  130         """Handle the call to a Bash app.
  131 
  132         Args:
  133              - Arbitrary
  134 
  135         Kwargs:
  136              - Arbitrary
  137 
  138         Returns:
  139              If outputs=[...] was a kwarg then:
  140                    App_fut, [Data_Futures...]
  141              else:
  142                    App_fut
  143 
  144         """
  145         # Update kwargs in the app definition with ones passed in at calltime
  146         self.kwargs.update(kwargs)
  147 
  148         if self.data_flow_kernel is None:
  149             dfk = DataFlowKernelLoader.dfk()
  150         else:
  151             dfk = self.data_flow_kernel
  152 
  153         app_fut = dfk.submit(wrap_error(remote_side_bash_executor), self.func, *args,
  154                              executors=self.executors,
  155                              fn_hash=self.func_hash,
  156                              cache=self.cache,
  157                              **self.kwargs)
  158 
  159         out_futs = [DataFuture(app_fut, o, tid=app_fut.tid)
  160                     for o in kwargs.get('outputs', [])]
  161         app_fut._outputs = out_futs
  162 
  163         return app_fut
  164
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/parsl/app/bash.py b/parsl/app/bash.py
  --- a/parsl/app/bash.py
  +++ b/parsl/app/bash.py
  @@ -1,6 +1,7 @@
   import logging
  -
  +from functools import update_wrapper
   from inspect import signature, Parameter
  +
   from parsl.app.errors import wrap_error
   from parsl.app.futures import DataFuture
   from parsl.app.app import AppBase
  @@ -150,7 +151,8 @@
           else:
               dfk = self.data_flow_kernel
   
  -        app_fut = dfk.submit(wrap_error(remote_side_bash_executor), self.func, *args,
  +        app_fut = dfk.submit(wrap_error(update_wrapper(remote_side_bash_executor, self.func)),
  +                             self.func, *args,
                                executors=self.executors,
                                fn_hash=self.func_hash,
                                cache=self.cache,
  
verification_info: {"golden_diff": "diff --git a/parsl/app/bash.py b/parsl/app/bash.py\n--- a/parsl/app/bash.py\n+++ b/parsl/app/bash.py\n@@ -1,6 +1,7 @@\n import logging\n-\n+from functools import update_wrapper\n from inspect import signature, Parameter\n+\n from parsl.app.errors import wrap_error\n from parsl.app.futures import DataFuture\n from parsl.app.app import AppBase\n@@ -150,7 +151,8 @@\n         else:\n             dfk = self.data_flow_kernel\n \n-        app_fut = dfk.submit(wrap_error(remote_side_bash_executor), self.func, *args,\n+        app_fut = dfk.submit(wrap_error(update_wrapper(remote_side_bash_executor, self.func)),\n+                             self.func, *args,\n                              executors=self.executors,\n                              fn_hash=self.func_hash,\n                              cache=self.cache,\n", "issue": "Properly handle func names for bash apps\nAt the moment bash apps are always `remote_side_bash_executor` in the monitoring DB because that is what is actually running. We should pass through the name of the app's function instead.\n", "before_files": [{"content": "import logging\n\nfrom inspect import signature, Parameter\nfrom parsl.app.errors import wrap_error\nfrom parsl.app.futures import DataFuture\nfrom parsl.app.app import AppBase\nfrom parsl.dataflow.dflow import DataFlowKernelLoader\n\nlogger = logging.getLogger(__name__)\n\n\ndef remote_side_bash_executor(func, *args, **kwargs):\n    \"\"\"Execute the bash app type function and return the command line string.\n\n    This string is reformatted with the *args, and **kwargs\n    from call time.\n    \"\"\"\n    import os\n    import time\n    import subprocess\n    import logging\n    import parsl.app.errors as pe\n\n    logging.basicConfig(filename='/tmp/bashexec.{0}.log'.format(time.time()), level=logging.DEBUG)\n\n    # start_t = time.time()\n\n    func_name = func.__name__\n\n    partial_cmdline = None\n\n    # Try to run the func to compose the commandline\n    try:\n        # Execute the func to get the commandline\n        partial_cmdline = func(*args, **kwargs)\n        # Reformat the commandline with current args and kwargs\n        executable = partial_cmdline.format(*args, **kwargs)\n\n    except AttributeError as e:\n        if partial_cmdline is not None:\n            raise pe.AppBadFormatting(\"App formatting failed for app '{}' with AttributeError: {}\".format(func_name, e))\n        else:\n            raise pe.BashAppNoReturn(\"Bash app '{}' did not return a value, or returned none - with this exception: {}\".format(func_name, e), None)\n\n    except IndexError as e:\n        raise pe.AppBadFormatting(\"App formatting failed for app '{}' with IndexError: {}\".format(func_name, e))\n    except Exception as e:\n        logging.error(\"Caught exception during formatting of app '{}': {}\".format(func_name, e))\n        raise e\n\n    logging.debug(\"Executable: %s\", executable)\n\n    # Updating stdout, stderr if values passed at call time.\n\n    def open_std_fd(fdname):\n        # fdname is 'stdout' or 'stderr'\n        stdfspec = kwargs.get(fdname)  # spec is str name or tuple (name, mode)\n        if stdfspec is None:\n            return None\n        elif isinstance(stdfspec, str):\n            fname = stdfspec\n            mode = 'a+'\n        elif isinstance(stdfspec, tuple):\n            if len(stdfspec) != 2:\n                raise pe.BadStdStreamFile(\"std descriptor %s has incorrect tuple length %s\" % (fdname, len(stdfspec)), TypeError('Bad Tuple Length'))\n            fname, mode = stdfspec\n        else:\n            raise pe.BadStdStreamFile(\"std descriptor %s has unexpected type %s\" % (fdname, str(type(stdfspec))), TypeError('Bad Tuple Type'))\n        try:\n            fd = open(fname, mode)\n        except Exception as e:\n            raise pe.BadStdStreamFile(fname, e)\n        return fd\n\n    std_out = open_std_fd('stdout')\n    std_err = open_std_fd('stderr')\n    timeout = kwargs.get('walltime')\n\n    returncode = None\n    try:\n        proc = subprocess.Popen(executable, stdout=std_out, stderr=std_err, shell=True, executable='/bin/bash')\n        proc.wait(timeout=timeout)\n        returncode = proc.returncode\n\n    except subprocess.TimeoutExpired:\n        # print(\"Timeout\")\n        raise pe.AppTimeout(\"[{}] App exceeded walltime: {}\".format(func_name, timeout))\n\n    except Exception as e:\n        # print(\"Caught exception: \", e)\n        raise pe.AppException(\"[{}] App caught exception: {}\".format(func_name, proc.returncode), e)\n\n    if returncode != 0:\n        raise pe.AppFailure(\"[{}] App failed with exit code: {}\".format(func_name, proc.returncode), proc.returncode)\n\n    # TODO : Add support for globs here\n\n    missing = []\n    for outputfile in kwargs.get('outputs', []):\n        fpath = outputfile\n        if type(outputfile) != str:\n            fpath = outputfile.filepath\n\n        if not os.path.exists(fpath):\n            missing.extend([outputfile])\n\n    if missing:\n        raise pe.MissingOutputs(\"[{}] Missing outputs\".format(func_name), missing)\n\n    # exec_duration = time.time() - start_t\n    return returncode\n\n\nclass BashApp(AppBase):\n\n    def __init__(self, func, data_flow_kernel=None, walltime=60, cache=False, executors='all'):\n        super().__init__(func, data_flow_kernel=data_flow_kernel, walltime=60, executors=executors, cache=cache)\n        self.kwargs = {}\n\n        # We duplicate the extraction of parameter defaults\n        # to self.kwargs to ensure availability at point of\n        # command string format. Refer: #349\n        sig = signature(func)\n\n        for s in sig.parameters:\n            if sig.parameters[s].default != Parameter.empty:\n                self.kwargs[s] = sig.parameters[s].default\n\n    def __call__(self, *args, **kwargs):\n        \"\"\"Handle the call to a Bash app.\n\n        Args:\n             - Arbitrary\n\n        Kwargs:\n             - Arbitrary\n\n        Returns:\n             If outputs=[...] was a kwarg then:\n                   App_fut, [Data_Futures...]\n             else:\n                   App_fut\n\n        \"\"\"\n        # Update kwargs in the app definition with ones passed in at calltime\n        self.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        app_fut = dfk.submit(wrap_error(remote_side_bash_executor), self.func, *args,\n                             executors=self.executors,\n                             fn_hash=self.func_hash,\n                             cache=self.cache,\n                             **self.kwargs)\n\n        out_futs = [DataFuture(app_fut, o, tid=app_fut.tid)\n                    for o in kwargs.get('outputs', [])]\n        app_fut._outputs = out_futs\n\n        return app_fut\n", "path": "parsl/app/bash.py"}], "after_files": [{"content": "import logging\nfrom functools import update_wrapper\nfrom inspect import signature, Parameter\n\nfrom parsl.app.errors import wrap_error\nfrom parsl.app.futures import DataFuture\nfrom parsl.app.app import AppBase\nfrom parsl.dataflow.dflow import DataFlowKernelLoader\n\nlogger = logging.getLogger(__name__)\n\n\ndef remote_side_bash_executor(func, *args, **kwargs):\n    \"\"\"Execute the bash app type function and return the command line string.\n\n    This string is reformatted with the *args, and **kwargs\n    from call time.\n    \"\"\"\n    import os\n    import time\n    import subprocess\n    import logging\n    import parsl.app.errors as pe\n\n    logging.basicConfig(filename='/tmp/bashexec.{0}.log'.format(time.time()), level=logging.DEBUG)\n\n    # start_t = time.time()\n\n    func_name = func.__name__\n\n    partial_cmdline = None\n\n    # Try to run the func to compose the commandline\n    try:\n        # Execute the func to get the commandline\n        partial_cmdline = func(*args, **kwargs)\n        # Reformat the commandline with current args and kwargs\n        executable = partial_cmdline.format(*args, **kwargs)\n\n    except AttributeError as e:\n        if partial_cmdline is not None:\n            raise pe.AppBadFormatting(\"App formatting failed for app '{}' with AttributeError: {}\".format(func_name, e))\n        else:\n            raise pe.BashAppNoReturn(\"Bash app '{}' did not return a value, or returned none - with this exception: {}\".format(func_name, e), None)\n\n    except IndexError as e:\n        raise pe.AppBadFormatting(\"App formatting failed for app '{}' with IndexError: {}\".format(func_name, e))\n    except Exception as e:\n        logging.error(\"Caught exception during formatting of app '{}': {}\".format(func_name, e))\n        raise e\n\n    logging.debug(\"Executable: %s\", executable)\n\n    # Updating stdout, stderr if values passed at call time.\n\n    def open_std_fd(fdname):\n        # fdname is 'stdout' or 'stderr'\n        stdfspec = kwargs.get(fdname)  # spec is str name or tuple (name, mode)\n        if stdfspec is None:\n            return None\n        elif isinstance(stdfspec, str):\n            fname = stdfspec\n            mode = 'a+'\n        elif isinstance(stdfspec, tuple):\n            if len(stdfspec) != 2:\n                raise pe.BadStdStreamFile(\"std descriptor %s has incorrect tuple length %s\" % (fdname, len(stdfspec)), TypeError('Bad Tuple Length'))\n            fname, mode = stdfspec\n        else:\n            raise pe.BadStdStreamFile(\"std descriptor %s has unexpected type %s\" % (fdname, str(type(stdfspec))), TypeError('Bad Tuple Type'))\n        try:\n            fd = open(fname, mode)\n        except Exception as e:\n            raise pe.BadStdStreamFile(fname, e)\n        return fd\n\n    std_out = open_std_fd('stdout')\n    std_err = open_std_fd('stderr')\n    timeout = kwargs.get('walltime')\n\n    returncode = None\n    try:\n        proc = subprocess.Popen(executable, stdout=std_out, stderr=std_err, shell=True, executable='/bin/bash')\n        proc.wait(timeout=timeout)\n        returncode = proc.returncode\n\n    except subprocess.TimeoutExpired:\n        # print(\"Timeout\")\n        raise pe.AppTimeout(\"[{}] App exceeded walltime: {}\".format(func_name, timeout))\n\n    except Exception as e:\n        # print(\"Caught exception: \", e)\n        raise pe.AppException(\"[{}] App caught exception: {}\".format(func_name, proc.returncode), e)\n\n    if returncode != 0:\n        raise pe.AppFailure(\"[{}] App failed with exit code: {}\".format(func_name, proc.returncode), proc.returncode)\n\n    # TODO : Add support for globs here\n\n    missing = []\n    for outputfile in kwargs.get('outputs', []):\n        fpath = outputfile\n        if type(outputfile) != str:\n            fpath = outputfile.filepath\n\n        if not os.path.exists(fpath):\n            missing.extend([outputfile])\n\n    if missing:\n        raise pe.MissingOutputs(\"[{}] Missing outputs\".format(func_name), missing)\n\n    # exec_duration = time.time() - start_t\n    return returncode\n\n\nclass BashApp(AppBase):\n\n    def __init__(self, func, data_flow_kernel=None, walltime=60, cache=False, executors='all'):\n        super().__init__(func, data_flow_kernel=data_flow_kernel, walltime=60, executors=executors, cache=cache)\n        self.kwargs = {}\n\n        # We duplicate the extraction of parameter defaults\n        # to self.kwargs to ensure availability at point of\n        # command string format. Refer: #349\n        sig = signature(func)\n\n        for s in sig.parameters:\n            if sig.parameters[s].default != Parameter.empty:\n                self.kwargs[s] = sig.parameters[s].default\n\n    def __call__(self, *args, **kwargs):\n        \"\"\"Handle the call to a Bash app.\n\n        Args:\n             - Arbitrary\n\n        Kwargs:\n             - Arbitrary\n\n        Returns:\n             If outputs=[...] was a kwarg then:\n                   App_fut, [Data_Futures...]\n             else:\n                   App_fut\n\n        \"\"\"\n        # Update kwargs in the app definition with ones passed in at calltime\n        self.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        app_fut = dfk.submit(wrap_error(update_wrapper(remote_side_bash_executor, self.func)),\n                             self.func, *args,\n                             executors=self.executors,\n                             fn_hash=self.func_hash,\n                             cache=self.cache,\n                             **self.kwargs)\n\n        out_futs = [DataFuture(app_fut, o, tid=app_fut.tid)\n                    for o in kwargs.get('outputs', [])]\n        app_fut._outputs = out_futs\n\n        return app_fut\n", "path": "parsl/app/bash.py"}]}