prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Passing Files breaks over IPP
  The new File class contains a dictionary that maps DataFutures for each site to which it is being staged and contains a reference to the DataManager. Neither of these are pickle-able.
  
  So if we do something like this :+1: 
  ```
  data = File("foo.txt")
  fu = remote_app(inputs=[data])
  fu.result() # <--- We'll get an error from here
  ```
  Here's the relevant piece from the exception traceback :
  ```
  File "/usr/local/lib/python3.5/dist-packages/ipyparallel/serialize/serialize.py", line 112, in serialize_object
     buffers.insert(0, pickle.dumps(cobj, PICKLE_PROTOCOL))
  TypeError: can't pickle _thread.lock objects
  ```
  
  I believe that the File object is the best place to hold the Future information about itself, and that would give us the opportunity to do smarter file staging in the future. So I propose that we fix this with a custom pickler for the File class.
  
  This is blocker for 0.5.0.
  
  --- 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/data_provider/files.py`
  Content:
  ```
  1 """Define the File Type.
  2 
  3 The primary purpose of the File object is to track the protocol to be used
  4 to transfer the file as well as to give the appropriate filepath depending
  5 on where(client-side, remote-side, intermediary-side) the File.filepath is
  6 being called from
  7 """
  8 
  9 import os
  10 import logging
  11 from urllib.parse import urlparse
  12 from parsl.data_provider.data_manager import DataManager
  13 
  14 
  15 logger = logging.getLogger(__name__)
  16 
  17 
  18 class File(str):
  19     """The Parsl File Class.
  20 
  21     This is planned to be a very simple class that simply
  22     captures various attributes of a file, and relies on client-side and worker-side
  23     systems to enable to appropriate transfer of files.
  24     """
  25 
  26     def __init__(self, url, dman=None, cache=False, caching_dir=".", staging='direct'):
  27         """Construct a File object from a url string.
  28 
  29         Args:
  30            - url (string) : url string of the file e.g.
  31               - 'input.txt'
  32               - 'file:///scratch/proj101/input.txt'
  33               - 'globus://go#ep1/~/data/input.txt'
  34               - 'globus://ddb59aef-6d04-11e5-ba46-22000b92c6ec/home/johndoe/data/input.txt'
  35            - dman (DataManager) : data manager
  36         """
  37         self.url = url
  38         parsed_url = urlparse(self.url)
  39         self.scheme = parsed_url.scheme if parsed_url.scheme else 'file'
  40         self.netloc = parsed_url.netloc
  41         self.path = parsed_url.path
  42         self.filename = os.path.basename(self.path)
  43         self.dman = dman if dman else DataManager.get_data_manager()
  44         self.data_future = {}
  45         if self.scheme != 'file':
  46             self.dman.add_file(self)
  47 
  48         self.cache = cache
  49         self.caching_dir = caching_dir
  50         self.staging = staging
  51 
  52     def __str__(self):
  53         return self.filepath
  54 
  55     def __repr__(self):
  56         return self.__str__()
  57 
  58     def __fspath__(self):
  59         return self.filepath
  60 
  61     @property
  62     def filepath(self):
  63         """Return the resolved filepath on the side where it is called from.
  64 
  65         The appropriate filepath will be returned when called from within
  66         an app running remotely as well as regular python on the client side.
  67 
  68         Args:
  69             - self
  70         Returns:
  71              - filepath (string)
  72         """
  73         if self.scheme == 'globus':
  74             if hasattr(self, 'local_path'):
  75                 return self.local_path
  76 
  77         if 'exec_site' not in globals() or self.staging == 'direct':
  78             # Assume local and direct
  79             return self.path
  80         else:
  81             # Return self.path for now
  82             return self.path
  83 
  84     def stage_in(self, site=None):
  85         """Transport file from the site of origin to local site."""
  86         return self.dman.stage_in(self, site)
  87 
  88     def stage_out(self):
  89         """Transport file from local filesystem to origin site."""
  90         return self.dman.stage_out(self)
  91 
  92     def set_data_future(self, df, site=None):
  93         self.data_future[site] = df
  94 
  95     def get_data_future(self, site):
  96         return self.data_future.get(site)
  97 
  98 
  99 if __name__ == '__main__':
  100 
  101     x = File('./files.py')
  102
  ```
  --- 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/data_provider/files.py b/parsl/data_provider/files.py
  --- a/parsl/data_provider/files.py
  +++ b/parsl/data_provider/files.py
  @@ -95,6 +95,34 @@
       def get_data_future(self, site):
           return self.data_future.get(site)
   
  +    def __getstate__(self):
  +        """ Overriding the default pickling method.
  +
  +        The File object get's pickled and transmitted to remote sites during app
  +        execution. This enables pickling while retaining the lockable resources
  +        to the DFK/Client side.
  +        """
  +
  +        state = self.__dict__.copy()
  +
  +        # We have already made a copy of the future objects, they are now no longer
  +        # reliable as means to wait for the staging events
  +        for site in state["data_future"]:
  +            # This is assumed to be safe, since the data_future represents staging to a specific site
  +            # and a site will only have one filepath.
  +            state["data_future"][site] = state["data_future"][site].filepath
  +
  +        state["dman"] = None
  +
  +        return state
  +
  +    def __setstate__(self, state):
  +        """ Overloading the default pickle method to reconstruct a File from serialized form
  +
  +        This might require knowledge of whethere a DataManager is already present in the context.
  +        """
  +        self.__dict__.update(state)
  +
   
   if __name__ == '__main__':
  
verification_info: {"golden_diff": "diff --git a/parsl/data_provider/files.py b/parsl/data_provider/files.py\n--- a/parsl/data_provider/files.py\n+++ b/parsl/data_provider/files.py\n@@ -95,6 +95,34 @@\n     def get_data_future(self, site):\n         return self.data_future.get(site)\n \n+    def __getstate__(self):\n+        \"\"\" Overriding the default pickling method.\n+\n+        The File object get's pickled and transmitted to remote sites during app\n+        execution. This enables pickling while retaining the lockable resources\n+        to the DFK/Client side.\n+        \"\"\"\n+\n+        state = self.__dict__.copy()\n+\n+        # We have already made a copy of the future objects, they are now no longer\n+        # reliable as means to wait for the staging events\n+        for site in state[\"data_future\"]:\n+            # This is assumed to be safe, since the data_future represents staging to a specific site\n+            # and a site will only have one filepath.\n+            state[\"data_future\"][site] = state[\"data_future\"][site].filepath\n+\n+        state[\"dman\"] = None\n+\n+        return state\n+\n+    def __setstate__(self, state):\n+        \"\"\" Overloading the default pickle method to reconstruct a File from serialized form\n+\n+        This might require knowledge of whethere a DataManager is already present in the context.\n+        \"\"\"\n+        self.__dict__.update(state)\n+\n \n if __name__ == '__main__':\n", "issue": "Passing Files breaks over IPP\nThe new File class contains a dictionary that maps DataFutures for each site to which it is being staged and contains a reference to the DataManager. Neither of these are pickle-able.\r\n\r\nSo if we do something like this :+1: \r\n```\r\ndata = File(\"foo.txt\")\r\nfu = remote_app(inputs=[data])\r\nfu.result() # <--- We'll get an error from here\r\n```\r\nHere's the relevant piece from the exception traceback :\r\n```\r\nFile \"/usr/local/lib/python3.5/dist-packages/ipyparallel/serialize/serialize.py\", line 112, in serialize_object\r\n   buffers.insert(0, pickle.dumps(cobj, PICKLE_PROTOCOL))\r\nTypeError: can't pickle _thread.lock objects\r\n```\r\n\r\nI believe that the File object is the best place to hold the Future information about itself, and that would give us the opportunity to do smarter file staging in the future. So I propose that we fix this with a custom pickler for the File class.\r\n\r\nThis is blocker for 0.5.0.\n", "before_files": [{"content": "\"\"\"Define the File Type.\n\nThe primary purpose of the File object is to track the protocol to be used\nto transfer the file as well as to give the appropriate filepath depending\non where(client-side, remote-side, intermediary-side) the File.filepath is\nbeing called from\n\"\"\"\n\nimport os\nimport logging\nfrom urllib.parse import urlparse\nfrom parsl.data_provider.data_manager import DataManager\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass File(str):\n    \"\"\"The Parsl File Class.\n\n    This is planned to be a very simple class that simply\n    captures various attributes of a file, and relies on client-side and worker-side\n    systems to enable to appropriate transfer of files.\n    \"\"\"\n\n    def __init__(self, url, dman=None, cache=False, caching_dir=\".\", staging='direct'):\n        \"\"\"Construct a File object from a url string.\n\n        Args:\n           - url (string) : url string of the file e.g.\n              - 'input.txt'\n              - 'file:///scratch/proj101/input.txt'\n              - 'globus://go#ep1/~/data/input.txt'\n              - 'globus://ddb59aef-6d04-11e5-ba46-22000b92c6ec/home/johndoe/data/input.txt'\n           - dman (DataManager) : data manager\n        \"\"\"\n        self.url = url\n        parsed_url = urlparse(self.url)\n        self.scheme = parsed_url.scheme if parsed_url.scheme else 'file'\n        self.netloc = parsed_url.netloc\n        self.path = parsed_url.path\n        self.filename = os.path.basename(self.path)\n        self.dman = dman if dman else DataManager.get_data_manager()\n        self.data_future = {}\n        if self.scheme != 'file':\n            self.dman.add_file(self)\n\n        self.cache = cache\n        self.caching_dir = caching_dir\n        self.staging = staging\n\n    def __str__(self):\n        return self.filepath\n\n    def __repr__(self):\n        return self.__str__()\n\n    def __fspath__(self):\n        return self.filepath\n\n    @property\n    def filepath(self):\n        \"\"\"Return the resolved filepath on the side where it is called from.\n\n        The appropriate filepath will be returned when called from within\n        an app running remotely as well as regular python on the client side.\n\n        Args:\n            - self\n        Returns:\n             - filepath (string)\n        \"\"\"\n        if self.scheme == 'globus':\n            if hasattr(self, 'local_path'):\n                return self.local_path\n\n        if 'exec_site' not in globals() or self.staging == 'direct':\n            # Assume local and direct\n            return self.path\n        else:\n            # Return self.path for now\n            return self.path\n\n    def stage_in(self, site=None):\n        \"\"\"Transport file from the site of origin to local site.\"\"\"\n        return self.dman.stage_in(self, site)\n\n    def stage_out(self):\n        \"\"\"Transport file from local filesystem to origin site.\"\"\"\n        return self.dman.stage_out(self)\n\n    def set_data_future(self, df, site=None):\n        self.data_future[site] = df\n\n    def get_data_future(self, site):\n        return self.data_future.get(site)\n\n\nif __name__ == '__main__':\n\n    x = File('./files.py')\n", "path": "parsl/data_provider/files.py"}], "after_files": [{"content": "\"\"\"Define the File Type.\n\nThe primary purpose of the File object is to track the protocol to be used\nto transfer the file as well as to give the appropriate filepath depending\non where(client-side, remote-side, intermediary-side) the File.filepath is\nbeing called from\n\"\"\"\n\nimport os\nimport logging\nfrom urllib.parse import urlparse\nfrom parsl.data_provider.data_manager import DataManager\n\n\nlogger = logging.getLogger(__name__)\n\n\nclass File(str):\n    \"\"\"The Parsl File Class.\n\n    This is planned to be a very simple class that simply\n    captures various attributes of a file, and relies on client-side and worker-side\n    systems to enable to appropriate transfer of files.\n    \"\"\"\n\n    def __init__(self, url, dman=None, cache=False, caching_dir=\".\", staging='direct'):\n        \"\"\"Construct a File object from a url string.\n\n        Args:\n           - url (string) : url string of the file e.g.\n              - 'input.txt'\n              - 'file:///scratch/proj101/input.txt'\n              - 'globus://go#ep1/~/data/input.txt'\n              - 'globus://ddb59aef-6d04-11e5-ba46-22000b92c6ec/home/johndoe/data/input.txt'\n           - dman (DataManager) : data manager\n        \"\"\"\n        self.url = url\n        parsed_url = urlparse(self.url)\n        self.scheme = parsed_url.scheme if parsed_url.scheme else 'file'\n        self.netloc = parsed_url.netloc\n        self.path = parsed_url.path\n        self.filename = os.path.basename(self.path)\n        self.dman = dman if dman else DataManager.get_data_manager()\n        self.data_future = {}\n        if self.scheme != 'file':\n            self.dman.add_file(self)\n\n        self.cache = cache\n        self.caching_dir = caching_dir\n        self.staging = staging\n\n    def __str__(self):\n        return self.filepath\n\n    def __repr__(self):\n        return self.__str__()\n\n    def __fspath__(self):\n        return self.filepath\n\n    @property\n    def filepath(self):\n        \"\"\"Return the resolved filepath on the side where it is called from.\n\n        The appropriate filepath will be returned when called from within\n        an app running remotely as well as regular python on the client side.\n\n        Args:\n            - self\n        Returns:\n             - filepath (string)\n        \"\"\"\n        if self.scheme == 'globus':\n            if hasattr(self, 'local_path'):\n                return self.local_path\n\n        if 'exec_site' not in globals() or self.staging == 'direct':\n            # Assume local and direct\n            return self.path\n        else:\n            # Return self.path for now\n            return self.path\n\n    def stage_in(self, site=None):\n        \"\"\"Transport file from the site of origin to local site.\"\"\"\n        return self.dman.stage_in(self, site)\n\n    def stage_out(self):\n        \"\"\"Transport file from local filesystem to origin site.\"\"\"\n        return self.dman.stage_out(self)\n\n    def set_data_future(self, df, site=None):\n        self.data_future[site] = df\n\n    def get_data_future(self, site):\n        return self.data_future.get(site)\n\n    def __getstate__(self):\n        \"\"\" Overriding the default pickling method.\n\n        The File object get's pickled and transmitted to remote sites during app\n        execution. This enables pickling while retaining the lockable resources\n        to the DFK/Client side.\n        \"\"\"\n\n        state = self.__dict__.copy()\n\n        # We have already made a copy of the future objects, they are now no longer\n        # reliable as means to wait for the staging events\n        for site in state[\"data_future\"]:\n            # This is assumed to be safe, since the data_future represents staging to a specific site\n            # and a site will only have one filepath.\n            state[\"data_future\"][site] = state[\"data_future\"][site].filepath\n\n        state[\"dman\"] = None\n\n        return state\n\n    def __setstate__(self, state):\n        \"\"\" Overloading the default pickle method to reconstruct a File from serialized form\n\n        This might require knowledge of whethere a DataManager is already present in the context.\n        \"\"\"\n        self.__dict__.update(state)\n\n\nif __name__ == '__main__':\n\n    x = File('./files.py')\n", "path": "parsl/data_provider/files.py"}]}