prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Parsl internal bugs silently squashed then hangs
  @benclifford reported an alarming bug in which a error in the parsl code does not throw an exception but is silently squashed. This is followed by the code hanging and not making progress. To make the situation even worse the strategy thread continues to run, giving the impression that parsl is doing something. 
  
  My suspicion is the the exception silently kills some thread, and that goes unreported.
  
  The string formatting bug added here (in memoization code) -> https://github.com/Parsl/parsl/tree/pr238-related-example reproduces this issue with a test script that hits this memoization code. 
  
  Some recommendations:
  1. Better exception handling
  2. Logs to show thread-ids so that we can see when threads have gone missing
  
  --- 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/__init__.py`
  Content:
  ```
  1 """Parsl is a Parallel Scripting Library, designed to enable efficient workflow execution.
  2 
  3 Importing
  4 ---------
  5 
  6 To get all the required functionality, we suggest importing the library as follows:
  7 
  8 >>> import parsl
  9 >>> from parsl import *
  10 
  11 Logging
  12 -------
  13 
  14 Following the general logging philosophy of python libraries, by default
  15 `Parsl <https://github.com/swift-lang/swift-e-lab/>`_ doesn't log anything.
  16 However the following helper functions are provided for logging:
  17 
  18 1. set_stream_logger
  19     This sets the logger to the StreamHandler. This is quite useful when working from
  20     a Jupyter notebook.
  21 
  22 2. set_file_logger
  23     This sets the logging to a file. This is ideal for reporting issues to the dev team.
  24 
  25 """
  26 import logging
  27 
  28 from parsl.version import VERSION
  29 from parsl.app.app import App
  30 from parsl.executors.threads import ThreadPoolExecutor
  31 from parsl.executors.ipp import IPyParallelExecutor
  32 from parsl.data_provider.files import File
  33 
  34 from parsl.dataflow.dflow import DataFlowKernel, DataFlowKernelLoader
  35 from parsl.app.app_factory import AppFactoryFactory
  36 APP_FACTORY_FACTORY = AppFactoryFactory('central')
  37 
  38 __author__ = 'Yadu Nand Babuji'
  39 __version__ = VERSION
  40 
  41 __all__ = [
  42     'App', 'DataFlowKernel', 'File', 'ThreadPoolExecutor',
  43     'IPyParallelExecutor', 'set_stream_logger', 'set_file_logger'
  44 ]
  45 
  46 clear = DataFlowKernelLoader.clear
  47 load = DataFlowKernelLoader.load
  48 dfk = DataFlowKernelLoader.dfk
  49 
  50 
  51 def set_stream_logger(name='parsl', level=logging.DEBUG, format_string=None):
  52     """Add a stream log handler.
  53 
  54     Args:
  55          - name (string) : Set the logger name.
  56          - level (logging.LEVEL) : Set to logging.DEBUG by default.
  57          - format_string (sting) : Set to None by default.
  58 
  59     Returns:
  60          - None
  61     """
  62     if format_string is None:
  63         # format_string = "%(asctime)s %(name)s [%(levelname)s] Thread:%(thread)d %(message)s"
  64         format_string = "%(asctime)s %(name)s:%(lineno)d [%(levelname)s]  %(message)s"
  65 
  66     logger = logging.getLogger(name)
  67     logger.setLevel(logging.DEBUG)
  68     handler = logging.StreamHandler()
  69     handler.setLevel(level)
  70     formatter = logging.Formatter(format_string, datefmt='%Y-%m-%d %H:%M:%S')
  71     handler.setFormatter(formatter)
  72     logger.addHandler(handler)
  73 
  74 
  75 def set_file_logger(filename, name='parsl', level=logging.DEBUG, format_string=None):
  76     """Add a stream log handler.
  77 
  78     Args:
  79         - filename (string): Name of the file to write logs to
  80         - name (string): Logger name
  81         - level (logging.LEVEL): Set the logging level.
  82         - format_string (string): Set the format string
  83 
  84     Returns:
  85        -  None
  86     """
  87     if format_string is None:
  88         format_string = "%(asctime)s %(name)s:%(lineno)d [%(levelname)s]  %(message)s"
  89 
  90     logger = logging.getLogger(name)
  91     logger.setLevel(logging.DEBUG)
  92     handler = logging.FileHandler(filename)
  93     handler.setLevel(level)
  94     formatter = logging.Formatter(format_string, datefmt='%Y-%m-%d %H:%M:%S')
  95     handler.setFormatter(formatter)
  96     logger.addHandler(handler)
  97 
  98 
  99 class NullHandler(logging.Handler):
  100     """Setup default logging to /dev/null since this is library."""
  101 
  102     def emit(self, record):
  103         pass
  104 
  105 
  106 logging.getLogger('parsl').addHandler(NullHandler())
  107
  ```
  --- 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/__init__.py b/parsl/__init__.py
  --- a/parsl/__init__.py
  +++ b/parsl/__init__.py
  @@ -71,6 +71,12 @@
       handler.setFormatter(formatter)
       logger.addHandler(handler)
   
  +    # Concurrent.futures errors are also of interest, as exceptions
  +    # which propagate out of the top of a callback are logged this way
  +    # and then discarded. (see #240)
  +    futures_logger = logging.getLogger("concurrent.futures")
  +    futures_logger.addHandler(handler)
  +
   
   def set_file_logger(filename, name='parsl', level=logging.DEBUG, format_string=None):
       """Add a stream log handler.
  @@ -95,6 +101,11 @@
       handler.setFormatter(formatter)
       logger.addHandler(handler)
   
  +    # see note in set_stream_logger for notes about logging
  +    # concurrent.futures
  +    futures_logger = logging.getLogger("concurrent.futures")
  +    futures_logger.addHandler(handler)
  +
   
   class NullHandler(logging.Handler):
       """Setup default logging to /dev/null since this is library."""
  
verification_info: {"golden_diff": "diff --git a/parsl/__init__.py b/parsl/__init__.py\n--- a/parsl/__init__.py\n+++ b/parsl/__init__.py\n@@ -71,6 +71,12 @@\n     handler.setFormatter(formatter)\n     logger.addHandler(handler)\n \n+    # Concurrent.futures errors are also of interest, as exceptions\n+    # which propagate out of the top of a callback are logged this way\n+    # and then discarded. (see #240)\n+    futures_logger = logging.getLogger(\"concurrent.futures\")\n+    futures_logger.addHandler(handler)\n+\n \n def set_file_logger(filename, name='parsl', level=logging.DEBUG, format_string=None):\n     \"\"\"Add a stream log handler.\n@@ -95,6 +101,11 @@\n     handler.setFormatter(formatter)\n     logger.addHandler(handler)\n \n+    # see note in set_stream_logger for notes about logging\n+    # concurrent.futures\n+    futures_logger = logging.getLogger(\"concurrent.futures\")\n+    futures_logger.addHandler(handler)\n+\n \n class NullHandler(logging.Handler):\n     \"\"\"Setup default logging to /dev/null since this is library.\"\"\"\n", "issue": "Parsl internal bugs silently squashed then hangs\n@benclifford reported an alarming bug in which a error in the parsl code does not throw an exception but is silently squashed. This is followed by the code hanging and not making progress. To make the situation even worse the strategy thread continues to run, giving the impression that parsl is doing something. \r\n\r\nMy suspicion is the the exception silently kills some thread, and that goes unreported.\r\n\r\nThe string formatting bug added here (in memoization code) -> https://github.com/Parsl/parsl/tree/pr238-related-example reproduces this issue with a test script that hits this memoization code. \r\n\r\nSome recommendations:\r\n1. Better exception handling\r\n2. Logs to show thread-ids so that we can see when threads have gone missing\n", "before_files": [{"content": "\"\"\"Parsl is a Parallel Scripting Library, designed to enable efficient workflow execution.\n\nImporting\n---------\n\nTo get all the required functionality, we suggest importing the library as follows:\n\n>>> import parsl\n>>> from parsl import *\n\nLogging\n-------\n\nFollowing the general logging philosophy of python libraries, by default\n`Parsl <https://github.com/swift-lang/swift-e-lab/>`_ doesn't log anything.\nHowever the following helper functions are provided for logging:\n\n1. set_stream_logger\n    This sets the logger to the StreamHandler. This is quite useful when working from\n    a Jupyter notebook.\n\n2. set_file_logger\n    This sets the logging to a file. This is ideal for reporting issues to the dev team.\n\n\"\"\"\nimport logging\n\nfrom parsl.version import VERSION\nfrom parsl.app.app import App\nfrom parsl.executors.threads import ThreadPoolExecutor\nfrom parsl.executors.ipp import IPyParallelExecutor\nfrom parsl.data_provider.files import File\n\nfrom parsl.dataflow.dflow import DataFlowKernel, DataFlowKernelLoader\nfrom parsl.app.app_factory import AppFactoryFactory\nAPP_FACTORY_FACTORY = AppFactoryFactory('central')\n\n__author__ = 'Yadu Nand Babuji'\n__version__ = VERSION\n\n__all__ = [\n    'App', 'DataFlowKernel', 'File', 'ThreadPoolExecutor',\n    'IPyParallelExecutor', 'set_stream_logger', 'set_file_logger'\n]\n\nclear = DataFlowKernelLoader.clear\nload = DataFlowKernelLoader.load\ndfk = DataFlowKernelLoader.dfk\n\n\ndef set_stream_logger(name='parsl', level=logging.DEBUG, format_string=None):\n    \"\"\"Add a stream log handler.\n\n    Args:\n         - name (string) : Set the logger name.\n         - level (logging.LEVEL) : Set to logging.DEBUG by default.\n         - format_string (sting) : Set to None by default.\n\n    Returns:\n         - None\n    \"\"\"\n    if format_string is None:\n        # format_string = \"%(asctime)s %(name)s [%(levelname)s] Thread:%(thread)d %(message)s\"\n        format_string = \"%(asctime)s %(name)s:%(lineno)d [%(levelname)s]  %(message)s\"\n\n    logger = logging.getLogger(name)\n    logger.setLevel(logging.DEBUG)\n    handler = logging.StreamHandler()\n    handler.setLevel(level)\n    formatter = logging.Formatter(format_string, datefmt='%Y-%m-%d %H:%M:%S')\n    handler.setFormatter(formatter)\n    logger.addHandler(handler)\n\n\ndef set_file_logger(filename, name='parsl', level=logging.DEBUG, format_string=None):\n    \"\"\"Add a stream log handler.\n\n    Args:\n        - filename (string): Name of the file to write logs to\n        - name (string): Logger name\n        - level (logging.LEVEL): Set the logging level.\n        - format_string (string): Set the format string\n\n    Returns:\n       -  None\n    \"\"\"\n    if format_string is None:\n        format_string = \"%(asctime)s %(name)s:%(lineno)d [%(levelname)s]  %(message)s\"\n\n    logger = logging.getLogger(name)\n    logger.setLevel(logging.DEBUG)\n    handler = logging.FileHandler(filename)\n    handler.setLevel(level)\n    formatter = logging.Formatter(format_string, datefmt='%Y-%m-%d %H:%M:%S')\n    handler.setFormatter(formatter)\n    logger.addHandler(handler)\n\n\nclass NullHandler(logging.Handler):\n    \"\"\"Setup default logging to /dev/null since this is library.\"\"\"\n\n    def emit(self, record):\n        pass\n\n\nlogging.getLogger('parsl').addHandler(NullHandler())\n", "path": "parsl/__init__.py"}], "after_files": [{"content": "\"\"\"Parsl is a Parallel Scripting Library, designed to enable efficient workflow execution.\n\nImporting\n---------\n\nTo get all the required functionality, we suggest importing the library as follows:\n\n>>> import parsl\n>>> from parsl import *\n\nLogging\n-------\n\nFollowing the general logging philosophy of python libraries, by default\n`Parsl <https://github.com/swift-lang/swift-e-lab/>`_ doesn't log anything.\nHowever the following helper functions are provided for logging:\n\n1. set_stream_logger\n    This sets the logger to the StreamHandler. This is quite useful when working from\n    a Jupyter notebook.\n\n2. set_file_logger\n    This sets the logging to a file. This is ideal for reporting issues to the dev team.\n\n\"\"\"\nimport logging\n\nfrom parsl.version import VERSION\nfrom parsl.app.app import App\nfrom parsl.executors.threads import ThreadPoolExecutor\nfrom parsl.executors.ipp import IPyParallelExecutor\nfrom parsl.data_provider.files import File\n\nfrom parsl.dataflow.dflow import DataFlowKernel, DataFlowKernelLoader\nfrom parsl.app.app_factory import AppFactoryFactory\nAPP_FACTORY_FACTORY = AppFactoryFactory('central')\n\n__author__ = 'Yadu Nand Babuji'\n__version__ = VERSION\n\n__all__ = [\n    'App', 'DataFlowKernel', 'File', 'ThreadPoolExecutor',\n    'IPyParallelExecutor', 'set_stream_logger', 'set_file_logger'\n]\n\nclear = DataFlowKernelLoader.clear\nload = DataFlowKernelLoader.load\ndfk = DataFlowKernelLoader.dfk\n\n\ndef set_stream_logger(name='parsl', level=logging.DEBUG, format_string=None):\n    \"\"\"Add a stream log handler.\n\n    Args:\n         - name (string) : Set the logger name.\n         - level (logging.LEVEL) : Set to logging.DEBUG by default.\n         - format_string (sting) : Set to None by default.\n\n    Returns:\n         - None\n    \"\"\"\n    if format_string is None:\n        # format_string = \"%(asctime)s %(name)s [%(levelname)s] Thread:%(thread)d %(message)s\"\n        format_string = \"%(asctime)s %(name)s:%(lineno)d [%(levelname)s]  %(message)s\"\n\n    logger = logging.getLogger(name)\n    logger.setLevel(logging.DEBUG)\n    handler = logging.StreamHandler()\n    handler.setLevel(level)\n    formatter = logging.Formatter(format_string, datefmt='%Y-%m-%d %H:%M:%S')\n    handler.setFormatter(formatter)\n    logger.addHandler(handler)\n\n    # Concurrent.futures errors are also of interest, as exceptions\n    # which propagate out of the top of a callback are logged this way\n    # and then discarded. (see #240)\n    futures_logger = logging.getLogger(\"concurrent.futures\")\n    futures_logger.addHandler(handler)\n\n\ndef set_file_logger(filename, name='parsl', level=logging.DEBUG, format_string=None):\n    \"\"\"Add a stream log handler.\n\n    Args:\n        - filename (string): Name of the file to write logs to\n        - name (string): Logger name\n        - level (logging.LEVEL): Set the logging level.\n        - format_string (string): Set the format string\n\n    Returns:\n       -  None\n    \"\"\"\n    if format_string is None:\n        format_string = \"%(asctime)s %(name)s:%(lineno)d [%(levelname)s]  %(message)s\"\n\n    logger = logging.getLogger(name)\n    logger.setLevel(logging.DEBUG)\n    handler = logging.FileHandler(filename)\n    handler.setLevel(level)\n    formatter = logging.Formatter(format_string, datefmt='%Y-%m-%d %H:%M:%S')\n    handler.setFormatter(formatter)\n    logger.addHandler(handler)\n\n    # see note in set_stream_logger for notes about logging\n    # concurrent.futures\n    futures_logger = logging.getLogger(\"concurrent.futures\")\n    futures_logger.addHandler(handler)\n\n\nclass NullHandler(logging.Handler):\n    \"\"\"Setup default logging to /dev/null since this is library.\"\"\"\n\n    def emit(self, record):\n        pass\n\n\nlogging.getLogger('parsl').addHandler(NullHandler())\n", "path": "parsl/__init__.py"}]}