We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unit Tests: `task` Directory


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `rastervision/utils/files.py`
Content:
```
1 import os
2 import shutil
3 from threading import Timer
4 import logging
5 
6 from google.protobuf import json_format
7 
8 from rastervision.filesystem.filesystem import FileSystem
9 from rastervision.filesystem.filesystem import ProtobufParseException
10 from rastervision.filesystem.local_filesystem import make_dir
11 
12 log = logging.getLogger(__name__)
13 
14 
15 def get_local_path(uri, download_dir, fs=None):
16     """Convert a URI into a corresponding local path.
17 
18     If a uri is local, return it. If it's remote, we generate a path for it
19     within download_dir. For an S3 path of form s3://<bucket>/<key>, the path
20     is <download_dir>/s3/<bucket>/<key>.
21 
22     Args:
23         uri: (string) URI of file
24         download_dir: (string) path to directory
25         fs: Optional FileSystem to use
26 
27     Returns:
28         (string) a local path
29     """
30     if uri is None:
31         return None
32 
33     if not fs:
34         fs = FileSystem.get_file_system(uri, 'r')
35     path = fs.local_path(uri, download_dir)
36 
37     return path
38 
39 
40 def sync_to_dir(src_dir_uri, dest_dir_uri, delete=False, fs=None):
41     """Synchronize a local to a local or remote directory.
42 
43     Transfers files from source to destination directories so that the
44     destination has all the source files. If delete is True, also delete
45     files in the destination to match those in the source directory.
46 
47     Args:
48         src_dir_uri: (string) URI of local source directory
49         dest_dir_uri: (string) URI of destination directory
50         delete: (bool)
51         fs: Optional FileSystem to use for destination
52     """
53     if not fs:
54         fs = FileSystem.get_file_system(dest_dir_uri, 'w')
55     fs.sync_to_dir(src_dir_uri, dest_dir_uri, delete=delete)
56 
57 
58 def sync_from_dir(src_dir_uri, dest_dir_uri, delete=False, fs=None):
59     """Synchronize a local or remote directory to a local directory.
60 
61     Transfers files from source to destination directories so that the
62     destination has all the source files. If delete is True, also delete
63     files in the destination to match those in the source directory.
64 
65     Args:
66         src_dir_uri: (string) URI of source directory
67         dest_dir_uri: (string) URI of local destination directory
68         delete: (bool)
69         fs: Optional FileSystem to use
70     """
71     if not fs:
72         fs = FileSystem.get_file_system(src_dir_uri, 'r')
73     fs.sync_from_dir(src_dir_uri, dest_dir_uri, delete=delete)
74 
75 
76 def start_sync(src_dir_uri, dest_dir_uri, sync_interval=600, fs=None):
77     """Start syncing a directory on a schedule.
78 
79     Calls sync_to_dir on a schedule.
80 
81     Args:
82         src_dir_uri: (string) Path of the local source directory
83         dest_dir_uri: (string) URI of destination directory
84         sync_interval: (int) period in seconds for syncing
85         fs:  Optional FileSystem to use
86     """
87 
88     def _sync_dir():
89         log.info('Syncing {} to {}...'.format(src_dir_uri, dest_dir_uri))
90         sync_to_dir(src_dir_uri, dest_dir_uri, delete=False, fs=fs)
91 
92     class SyncThread:
93         def __init__(self):
94             thread = Timer(sync_interval, _sync_dir)
95             thread.daemon = True
96             thread.start()
97             self.thread = thread
98 
99         def __enter__(self):
100             return self.thread
101 
102         def __exit__(self, type, value, traceback):
103             self.thread.cancel()
104 
105     return SyncThread()
106 
107 
108 def download_if_needed(uri, download_dir, fs=None):
109     """Download a file into a directory if it's remote.
110 
111     If uri is local, there is no need to download the file.
112 
113     Args:
114         uri: (string) URI of file
115         download_dir: (string) local directory to download file into
116         fs: Optional FileSystem to use.
117 
118     Returns:
119         (string) path to local file
120 
121     Raises:
122         NotReadableError if URI cannot be read from
123     """
124     if uri is None:
125         return None
126 
127     if not fs:
128         fs = FileSystem.get_file_system(uri, 'r')
129 
130     path = get_local_path(uri, download_dir, fs=fs)
131     make_dir(path, use_dirname=True)
132 
133     if path != uri:
134         log.info('Downloading {} to {}'.format(uri, path))
135 
136     fs.copy_from(uri, path)
137 
138     return path
139 
140 
141 def download_or_copy(uri, target_dir, fs=None):
142     """Downloads or copies a file to a directory
143 
144     Args:
145        uri: (string) URI of file
146        target_dir: (string) local directory to copy file to
147        fs: Optional FileSystem to use
148     """
149     local_path = download_if_needed(uri, target_dir, fs=fs)
150     shutil.copy(local_path, target_dir)
151     return local_path
152 
153 
154 def file_exists(uri, fs=None):
155     if not fs:
156         fs = FileSystem.get_file_system(uri, 'r')
157     return fs.file_exists(uri)
158 
159 
160 def list_paths(uri, ext=None, fs=None):
161     if uri is None:
162         return None
163 
164     if not fs:
165         fs = FileSystem.get_file_system(uri, 'r')
166 
167     return fs.list_paths(uri, ext=ext)
168 
169 
170 def upload_or_copy(src_path, dst_uri, fs=None):
171     """Upload a file if the destination is remote.
172 
173     If dst_uri is local, the file is copied.
174 
175     Args:
176         src_path: (string) path to source file
177         dst_uri: (string) URI of destination for file
178         fs: Optional FileSystem to use
179     Raises:
180         NotWritableError if URI cannot be written to
181     """
182     if dst_uri is None:
183         return
184 
185     if not (os.path.isfile(src_path) or os.path.isdir(src_path)):
186         raise Exception('{} does not exist.'.format(src_path))
187 
188     if not src_path == dst_uri:
189         log.info('Uploading {} to {}'.format(src_path, dst_uri))
190 
191     if not fs:
192         fs = FileSystem.get_file_system(dst_uri, 'w')
193     fs.copy_to(src_path, dst_uri)
194 
195 
196 def file_to_str(uri, fs=None):
197     """Download contents of text file into a string.
198 
199     Args:
200         uri: (string) URI of file
201         fs: Optional FileSystem to use
202 
203     Returns:
204         (string) with contents of text file
205 
206     Raises:
207         NotReadableError if URI cannot be read from
208     """
209     if not fs:
210         fs = FileSystem.get_file_system(uri, 'r')
211     return fs.read_str(uri)
212 
213 
214 def str_to_file(content_str, uri, fs=None):
215     """Writes string to text file.
216 
217     Args:
218         content_str: string to write
219         uri: (string) URI of file to write
220         fs: Optional FileSystem to use
221 
222     Raise:
223         NotWritableError if file_uri cannot be written
224     """
225     if not fs:
226         fs = FileSystem.get_file_system(uri, 'r')
227     return fs.write_str(uri, content_str)
228 
229 
230 def load_json_config(uri, message, fs=None):
231     """Load a JSON-formatted protobuf config file.
232 
233     Args:
234         uri: (string) URI of config file
235         message: (google.protobuf.message.Message) empty protobuf message of
236             to load the config into. The type needs to match the content of
237             uri.
238         fs: Optional FileSystem to use.
239 
240     Returns:
241         the same message passed as input with fields filled in from uri
242 
243     Raises:
244         ProtobufParseException if uri cannot be parsed
245     """
246     try:
247         return json_format.Parse(file_to_str(uri, fs=fs), message)
248     except json_format.ParseError as e:
249         error_msg = ('Problem parsing protobuf file {}. '.format(uri) +
250                      'You might need to run scripts/compile')
251         raise ProtobufParseException(error_msg) from e
252 
253 
254 def save_json_config(message, uri, fs=None):
255     """Save a protobuf object to a JSON file.
256 
257     Args:
258         message: (google.protobuf.message.Message) protobuf message
259         uri: (string) URI of JSON file to write message to
260         fs: Optional FileSystem to use
261 
262     Raises:
263         NotWritableError if uri cannot be written
264     """
265     json_str = json_format.MessageToJson(message)
266     str_to_file(json_str, uri, fs=fs)
267
```
--- 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/rastervision/utils/files.py b/rastervision/utils/files.py
--- a/rastervision/utils/files.py
+++ b/rastervision/utils/files.py
@@ -73,7 +73,8 @@
     fs.sync_from_dir(src_dir_uri, dest_dir_uri, delete=delete)
 
 
-def start_sync(src_dir_uri, dest_dir_uri, sync_interval=600, fs=None):
+def start_sync(src_dir_uri, dest_dir_uri, sync_interval=600,
+               fs=None):  # pragma: no cover
     """Start syncing a directory on a schedule.
 
     Calls sync_to_dir on a schedule.
@@ -157,7 +158,7 @@
     return fs.file_exists(uri)
 
 
-def list_paths(uri, ext=None, fs=None):
+def list_paths(uri, ext='', fs=None):
     if uri is None:
         return None

{"golden_diff": "diff --git a/rastervision/utils/files.py b/rastervision/utils/files.py\n--- a/rastervision/utils/files.py\n+++ b/rastervision/utils/files.py\n@@ -73,7 +73,8 @@\n     fs.sync_from_dir(src_dir_uri, dest_dir_uri, delete=delete)\n \n \n-def start_sync(src_dir_uri, dest_dir_uri, sync_interval=600, fs=None):\n+def start_sync(src_dir_uri, dest_dir_uri, sync_interval=600,\n+               fs=None):  # pragma: no cover\n     \"\"\"Start syncing a directory on a schedule.\n \n     Calls sync_to_dir on a schedule.\n@@ -157,7 +158,7 @@\n     return fs.file_exists(uri)\n \n \n-def list_paths(uri, ext=None, fs=None):\n+def list_paths(uri, ext='', fs=None):\n     if uri is None:\n         return None\n", "issue": "Unit Tests: `task` Directory\n\n", "before_files": [{"content": "import os\nimport shutil\nfrom threading import Timer\nimport logging\n\nfrom google.protobuf import json_format\n\nfrom rastervision.filesystem.filesystem import FileSystem\nfrom rastervision.filesystem.filesystem import ProtobufParseException\nfrom rastervision.filesystem.local_filesystem import make_dir\n\nlog = logging.getLogger(__name__)\n\n\ndef get_local_path(uri, download_dir, fs=None):\n    \"\"\"Convert a URI into a corresponding local path.\n\n    If a uri is local, return it. If it's remote, we generate a path for it\n    within download_dir. For an S3 path of form s3://<bucket>/<key>, the path\n    is <download_dir>/s3/<bucket>/<key>.\n\n    Args:\n        uri: (string) URI of file\n        download_dir: (string) path to directory\n        fs: Optional FileSystem to use\n\n    Returns:\n        (string) a local path\n    \"\"\"\n    if uri is None:\n        return None\n\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n    path = fs.local_path(uri, download_dir)\n\n    return path\n\n\ndef sync_to_dir(src_dir_uri, dest_dir_uri, delete=False, fs=None):\n    \"\"\"Synchronize a local to a local or remote directory.\n\n    Transfers files from source to destination directories so that the\n    destination has all the source files. If delete is True, also delete\n    files in the destination to match those in the source directory.\n\n    Args:\n        src_dir_uri: (string) URI of local source directory\n        dest_dir_uri: (string) URI of destination directory\n        delete: (bool)\n        fs: Optional FileSystem to use for destination\n    \"\"\"\n    if not fs:\n        fs = FileSystem.get_file_system(dest_dir_uri, 'w')\n    fs.sync_to_dir(src_dir_uri, dest_dir_uri, delete=delete)\n\n\ndef sync_from_dir(src_dir_uri, dest_dir_uri, delete=False, fs=None):\n    \"\"\"Synchronize a local or remote directory to a local directory.\n\n    Transfers files from source to destination directories so that the\n    destination has all the source files. If delete is True, also delete\n    files in the destination to match those in the source directory.\n\n    Args:\n        src_dir_uri: (string) URI of source directory\n        dest_dir_uri: (string) URI of local destination directory\n        delete: (bool)\n        fs: Optional FileSystem to use\n    \"\"\"\n    if not fs:\n        fs = FileSystem.get_file_system(src_dir_uri, 'r')\n    fs.sync_from_dir(src_dir_uri, dest_dir_uri, delete=delete)\n\n\ndef start_sync(src_dir_uri, dest_dir_uri, sync_interval=600, fs=None):\n    \"\"\"Start syncing a directory on a schedule.\n\n    Calls sync_to_dir on a schedule.\n\n    Args:\n        src_dir_uri: (string) Path of the local source directory\n        dest_dir_uri: (string) URI of destination directory\n        sync_interval: (int) period in seconds for syncing\n        fs:  Optional FileSystem to use\n    \"\"\"\n\n    def _sync_dir():\n        log.info('Syncing {} to {}...'.format(src_dir_uri, dest_dir_uri))\n        sync_to_dir(src_dir_uri, dest_dir_uri, delete=False, fs=fs)\n\n    class SyncThread:\n        def __init__(self):\n            thread = Timer(sync_interval, _sync_dir)\n            thread.daemon = True\n            thread.start()\n            self.thread = thread\n\n        def __enter__(self):\n            return self.thread\n\n        def __exit__(self, type, value, traceback):\n            self.thread.cancel()\n\n    return SyncThread()\n\n\ndef download_if_needed(uri, download_dir, fs=None):\n    \"\"\"Download a file into a directory if it's remote.\n\n    If uri is local, there is no need to download the file.\n\n    Args:\n        uri: (string) URI of file\n        download_dir: (string) local directory to download file into\n        fs: Optional FileSystem to use.\n\n    Returns:\n        (string) path to local file\n\n    Raises:\n        NotReadableError if URI cannot be read from\n    \"\"\"\n    if uri is None:\n        return None\n\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n\n    path = get_local_path(uri, download_dir, fs=fs)\n    make_dir(path, use_dirname=True)\n\n    if path != uri:\n        log.info('Downloading {} to {}'.format(uri, path))\n\n    fs.copy_from(uri, path)\n\n    return path\n\n\ndef download_or_copy(uri, target_dir, fs=None):\n    \"\"\"Downloads or copies a file to a directory\n\n    Args:\n       uri: (string) URI of file\n       target_dir: (string) local directory to copy file to\n       fs: Optional FileSystem to use\n    \"\"\"\n    local_path = download_if_needed(uri, target_dir, fs=fs)\n    shutil.copy(local_path, target_dir)\n    return local_path\n\n\ndef file_exists(uri, fs=None):\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n    return fs.file_exists(uri)\n\n\ndef list_paths(uri, ext=None, fs=None):\n    if uri is None:\n        return None\n\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n\n    return fs.list_paths(uri, ext=ext)\n\n\ndef upload_or_copy(src_path, dst_uri, fs=None):\n    \"\"\"Upload a file if the destination is remote.\n\n    If dst_uri is local, the file is copied.\n\n    Args:\n        src_path: (string) path to source file\n        dst_uri: (string) URI of destination for file\n        fs: Optional FileSystem to use\n    Raises:\n        NotWritableError if URI cannot be written to\n    \"\"\"\n    if dst_uri is None:\n        return\n\n    if not (os.path.isfile(src_path) or os.path.isdir(src_path)):\n        raise Exception('{} does not exist.'.format(src_path))\n\n    if not src_path == dst_uri:\n        log.info('Uploading {} to {}'.format(src_path, dst_uri))\n\n    if not fs:\n        fs = FileSystem.get_file_system(dst_uri, 'w')\n    fs.copy_to(src_path, dst_uri)\n\n\ndef file_to_str(uri, fs=None):\n    \"\"\"Download contents of text file into a string.\n\n    Args:\n        uri: (string) URI of file\n        fs: Optional FileSystem to use\n\n    Returns:\n        (string) with contents of text file\n\n    Raises:\n        NotReadableError if URI cannot be read from\n    \"\"\"\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n    return fs.read_str(uri)\n\n\ndef str_to_file(content_str, uri, fs=None):\n    \"\"\"Writes string to text file.\n\n    Args:\n        content_str: string to write\n        uri: (string) URI of file to write\n        fs: Optional FileSystem to use\n\n    Raise:\n        NotWritableError if file_uri cannot be written\n    \"\"\"\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n    return fs.write_str(uri, content_str)\n\n\ndef load_json_config(uri, message, fs=None):\n    \"\"\"Load a JSON-formatted protobuf config file.\n\n    Args:\n        uri: (string) URI of config file\n        message: (google.protobuf.message.Message) empty protobuf message of\n            to load the config into. The type needs to match the content of\n            uri.\n        fs: Optional FileSystem to use.\n\n    Returns:\n        the same message passed as input with fields filled in from uri\n\n    Raises:\n        ProtobufParseException if uri cannot be parsed\n    \"\"\"\n    try:\n        return json_format.Parse(file_to_str(uri, fs=fs), message)\n    except json_format.ParseError as e:\n        error_msg = ('Problem parsing protobuf file {}. '.format(uri) +\n                     'You might need to run scripts/compile')\n        raise ProtobufParseException(error_msg) from e\n\n\ndef save_json_config(message, uri, fs=None):\n    \"\"\"Save a protobuf object to a JSON file.\n\n    Args:\n        message: (google.protobuf.message.Message) protobuf message\n        uri: (string) URI of JSON file to write message to\n        fs: Optional FileSystem to use\n\n    Raises:\n        NotWritableError if uri cannot be written\n    \"\"\"\n    json_str = json_format.MessageToJson(message)\n    str_to_file(json_str, uri, fs=fs)\n", "path": "rastervision/utils/files.py"}], "after_files": [{"content": "import os\nimport shutil\nfrom threading import Timer\nimport logging\n\nfrom google.protobuf import json_format\n\nfrom rastervision.filesystem.filesystem import FileSystem\nfrom rastervision.filesystem.filesystem import ProtobufParseException\nfrom rastervision.filesystem.local_filesystem import make_dir\n\nlog = logging.getLogger(__name__)\n\n\ndef get_local_path(uri, download_dir, fs=None):\n    \"\"\"Convert a URI into a corresponding local path.\n\n    If a uri is local, return it. If it's remote, we generate a path for it\n    within download_dir. For an S3 path of form s3://<bucket>/<key>, the path\n    is <download_dir>/s3/<bucket>/<key>.\n\n    Args:\n        uri: (string) URI of file\n        download_dir: (string) path to directory\n        fs: Optional FileSystem to use\n\n    Returns:\n        (string) a local path\n    \"\"\"\n    if uri is None:\n        return None\n\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n    path = fs.local_path(uri, download_dir)\n\n    return path\n\n\ndef sync_to_dir(src_dir_uri, dest_dir_uri, delete=False, fs=None):\n    \"\"\"Synchronize a local to a local or remote directory.\n\n    Transfers files from source to destination directories so that the\n    destination has all the source files. If delete is True, also delete\n    files in the destination to match those in the source directory.\n\n    Args:\n        src_dir_uri: (string) URI of local source directory\n        dest_dir_uri: (string) URI of destination directory\n        delete: (bool)\n        fs: Optional FileSystem to use for destination\n    \"\"\"\n    if not fs:\n        fs = FileSystem.get_file_system(dest_dir_uri, 'w')\n    fs.sync_to_dir(src_dir_uri, dest_dir_uri, delete=delete)\n\n\ndef sync_from_dir(src_dir_uri, dest_dir_uri, delete=False, fs=None):\n    \"\"\"Synchronize a local or remote directory to a local directory.\n\n    Transfers files from source to destination directories so that the\n    destination has all the source files. If delete is True, also delete\n    files in the destination to match those in the source directory.\n\n    Args:\n        src_dir_uri: (string) URI of source directory\n        dest_dir_uri: (string) URI of local destination directory\n        delete: (bool)\n        fs: Optional FileSystem to use\n    \"\"\"\n    if not fs:\n        fs = FileSystem.get_file_system(src_dir_uri, 'r')\n    fs.sync_from_dir(src_dir_uri, dest_dir_uri, delete=delete)\n\n\ndef start_sync(src_dir_uri, dest_dir_uri, sync_interval=600,\n               fs=None):  # pragma: no cover\n    \"\"\"Start syncing a directory on a schedule.\n\n    Calls sync_to_dir on a schedule.\n\n    Args:\n        src_dir_uri: (string) Path of the local source directory\n        dest_dir_uri: (string) URI of destination directory\n        sync_interval: (int) period in seconds for syncing\n        fs:  Optional FileSystem to use\n    \"\"\"\n\n    def _sync_dir():\n        log.info('Syncing {} to {}...'.format(src_dir_uri, dest_dir_uri))\n        sync_to_dir(src_dir_uri, dest_dir_uri, delete=False, fs=fs)\n\n    class SyncThread:\n        def __init__(self):\n            thread = Timer(sync_interval, _sync_dir)\n            thread.daemon = True\n            thread.start()\n            self.thread = thread\n\n        def __enter__(self):\n            return self.thread\n\n        def __exit__(self, type, value, traceback):\n            self.thread.cancel()\n\n    return SyncThread()\n\n\ndef download_if_needed(uri, download_dir, fs=None):\n    \"\"\"Download a file into a directory if it's remote.\n\n    If uri is local, there is no need to download the file.\n\n    Args:\n        uri: (string) URI of file\n        download_dir: (string) local directory to download file into\n        fs: Optional FileSystem to use.\n\n    Returns:\n        (string) path to local file\n\n    Raises:\n        NotReadableError if URI cannot be read from\n    \"\"\"\n    if uri is None:\n        return None\n\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n\n    path = get_local_path(uri, download_dir, fs=fs)\n    make_dir(path, use_dirname=True)\n\n    if path != uri:\n        log.info('Downloading {} to {}'.format(uri, path))\n\n    fs.copy_from(uri, path)\n\n    return path\n\n\ndef download_or_copy(uri, target_dir, fs=None):\n    \"\"\"Downloads or copies a file to a directory\n\n    Args:\n       uri: (string) URI of file\n       target_dir: (string) local directory to copy file to\n       fs: Optional FileSystem to use\n    \"\"\"\n    local_path = download_if_needed(uri, target_dir, fs=fs)\n    shutil.copy(local_path, target_dir)\n    return local_path\n\n\ndef file_exists(uri, fs=None):\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n    return fs.file_exists(uri)\n\n\ndef list_paths(uri, ext='', fs=None):\n    if uri is None:\n        return None\n\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n\n    return fs.list_paths(uri, ext=ext)\n\n\ndef upload_or_copy(src_path, dst_uri, fs=None):\n    \"\"\"Upload a file if the destination is remote.\n\n    If dst_uri is local, the file is copied.\n\n    Args:\n        src_path: (string) path to source file\n        dst_uri: (string) URI of destination for file\n        fs: Optional FileSystem to use\n    Raises:\n        NotWritableError if URI cannot be written to\n    \"\"\"\n    if dst_uri is None:\n        return\n\n    if not (os.path.isfile(src_path) or os.path.isdir(src_path)):\n        raise Exception('{} does not exist.'.format(src_path))\n\n    if not src_path == dst_uri:\n        log.info('Uploading {} to {}'.format(src_path, dst_uri))\n\n    if not fs:\n        fs = FileSystem.get_file_system(dst_uri, 'w')\n    fs.copy_to(src_path, dst_uri)\n\n\ndef file_to_str(uri, fs=None):\n    \"\"\"Download contents of text file into a string.\n\n    Args:\n        uri: (string) URI of file\n        fs: Optional FileSystem to use\n\n    Returns:\n        (string) with contents of text file\n\n    Raises:\n        NotReadableError if URI cannot be read from\n    \"\"\"\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n    return fs.read_str(uri)\n\n\ndef str_to_file(content_str, uri, fs=None):\n    \"\"\"Writes string to text file.\n\n    Args:\n        content_str: string to write\n        uri: (string) URI of file to write\n        fs: Optional FileSystem to use\n\n    Raise:\n        NotWritableError if file_uri cannot be written\n    \"\"\"\n    if not fs:\n        fs = FileSystem.get_file_system(uri, 'r')\n    return fs.write_str(uri, content_str)\n\n\ndef load_json_config(uri, message, fs=None):\n    \"\"\"Load a JSON-formatted protobuf config file.\n\n    Args:\n        uri: (string) URI of config file\n        message: (google.protobuf.message.Message) empty protobuf message of\n            to load the config into. The type needs to match the content of\n            uri.\n        fs: Optional FileSystem to use.\n\n    Returns:\n        the same message passed as input with fields filled in from uri\n\n    Raises:\n        ProtobufParseException if uri cannot be parsed\n    \"\"\"\n    try:\n        return json_format.Parse(file_to_str(uri, fs=fs), message)\n    except json_format.ParseError as e:\n        error_msg = ('Problem parsing protobuf file {}. '.format(uri) +\n                     'You might need to run scripts/compile')\n        raise ProtobufParseException(error_msg) from e\n\n\ndef save_json_config(message, uri, fs=None):\n    \"\"\"Save a protobuf object to a JSON file.\n\n    Args:\n        message: (google.protobuf.message.Message) protobuf message\n        uri: (string) URI of JSON file to write message to\n        fs: Optional FileSystem to use\n\n    Raises:\n        NotWritableError if uri cannot be written\n    \"\"\"\n    json_str = json_format.MessageToJson(message)\n    str_to_file(json_str, uri, fs=fs)\n", "path": "rastervision/utils/files.py"}]}