We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Unused class FileWrapper
In the io manager module there is a FileWrapper class that seems to be never used anywhere?
Aside from the dubious utility of such a class (maybe if documented one could figure out) , maybe we should just remove it ?

@QCoDeS/core  ? 


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `qcodes/data/io.py`
Content:
```
1 """
2 IO managers for QCodes.
3 
4 IO managers wrap whatever physical storage layer the user wants to use
5 in an interface mimicking the built-in <open> context manager, with
6 some restrictions to minimize the overhead in creating new IO managers.
7 
8 The main thing these managers need to implement is the open context manager:
9 
10 - Only the context manager needs to be implemented, not separate
11   open function and close methods.
12 
13 - open takes the standard parameters:
14 
15     - filename: (string)
16     - mode: (string) only 'r' (read), 'w' (write), and 'a' (append) are
17       expected to be implemented. As with normal file objects, the only
18       difference between write and append is that write empties the file
19       before adding new data, and append leaves the existing contents in
20       place but starts writing at the end.
21     - encoding: If a special output encoding is desired. i.e. 'utf8
22 
23 - the file-like object returned should implement a minimal set of operations.
24 
25   In read mode:
26     - read([size]): read to the end or at most size bytes into a string
27     - readline([size]): read until a newline or up to size bytes, into a string
28     - iter(): usually return self, but can be any iterator over lines
29     - next(): assuming iter() returns self, this yields the next line.
30 
31     (note: iter and next can be constructed automatically by FileWrapper
32     if you implement readline.)
33 
34   In write or append mode:
35     - write(s): add string s to the end of the file.
36     - writelines(seq): add a sequence of strings (can be constructed
37       automatically if you use FileWrapper)
38 
39 IO managers should also implement:
40 
41 - a join method, ala os.path.join(\*args).
42 - a list method, that returns all objects matching location
43 - a remove method, ala os.remove(path) except that it will remove directories
44   as well as files, since we're allowing "locations" to be directories
45   or files.
46 """
47 
48 from contextlib import contextmanager
49 import os
50 import re
51 import shutil
52 from fnmatch import fnmatch
53 
54 ALLOWED_OPEN_MODES = ('r', 'w', 'a')
55 
56 
57 class DiskIO:
58 
59     """
60     Simple IO object to wrap disk operations with a custom base location.
61 
62     Also accepts both forward and backward slashes at any point, and
63     normalizes both to the OS we are currently on.
64 
65     Args:
66         base_location (str): a path to the root data folder.
67             Converted to an absolute path immediately, so even if you supply a
68             relative path, later changes to the OS working directory will not
69             affect data paths.
70     """
71 
72     def __init__(self, base_location):
73         if base_location is None:
74             self.base_location = None
75         else:
76             base_location = self._normalize_slashes(base_location)
77             self.base_location = os.path.abspath(base_location)
78 
79     @contextmanager
80     def open(self, filename, mode, encoding=None):
81         """
82         Mimic the interface of the built in open context manager.
83 
84         Args:
85             filename (str): path relative to base_location.
86 
87             mode (str): 'r' (read), 'w' (write), or 'a' (append).
88                 Other open modes are not supported because we don't want
89                 to force all IO managers to support others.
90 
91         Returns:
92             context manager yielding the open file
93         """
94         if mode not in ALLOWED_OPEN_MODES:
95             raise ValueError('mode {} not allowed in IO managers'.format(mode))
96 
97         filepath = self.to_path(filename)
98 
99         # make directories if needed
100         dirpath = os.path.dirname(filepath)
101         if not os.path.exists(dirpath):
102             os.makedirs(dirpath)
103 
104         # normally we'd construct this context manager with try/finally, but
105         # here we already have a context manager for open so we just wrap it
106         with open(filepath, mode, encoding=encoding) as f:
107             yield f
108 
109     def _normalize_slashes(self, location):
110         # note that this is NOT os.path.join - the difference is os.path.join
111         # discards empty strings, so if you use it on a re.split absolute
112         # path you will get a relative path!
113         return os.sep.join(re.split('[\\\\/]', location))
114 
115     def to_path(self, location):
116         """
117         Convert a location string into a path on the local file system.
118 
119         For DiskIO this just fixes slashes and prepends the base location,
120         doing nothing active with the file. But for other io managers that
121         refer to remote storage, this method may actually fetch the file and
122         put it at a temporary local path.
123 
124         Args:
125             location (str): A location string for a complete dataset or
126                 a file within it.
127 
128         Returns:
129             path (str): The path on disk to which this location maps.
130         """
131         location = self._normalize_slashes(location)
132         if self.base_location:
133             return os.path.join(self.base_location, location)
134         else:
135             return location
136 
137     def to_location(self, path):
138         """
139         Convert a local filesystem path into a location string.
140 
141         Args:
142             path (str): a path on the local file system.
143 
144         Returns:
145             location (str): the location string corresponding to this path.
146         """
147         if self.base_location:
148             return os.path.relpath(path, self.base_location)
149         else:
150             return path
151 
152     def __repr__(self):
153         """Show the base location in the repr."""
154         return '<DiskIO, base_location={}>'.format(repr(self.base_location))
155 
156     def join(self, *args):
157         """Context-dependent os.path.join for this io manager."""
158         return os.path.join(*list(map(self._normalize_slashes, args)))
159 
160     def isfile(self, location):
161         """Check whether this location matches a file."""
162         path = self.to_path(location)
163         return os.path.isfile(path)
164 
165     def list(self, location, maxdepth=1, include_dirs=False):
166         """
167         Return all files that match location.
168 
169         This is either files whose names match up to an arbitrary extension,
170         or any files within an exactly matching directory name.
171 
172         Args:
173             location (str): the location to match.
174                 May contain the usual path wildcards * and ?
175 
176             maxdepth (int, optional): maximum levels of directory nesting to
177                 recurse into looking for files. Default 1.
178 
179             include_dirs (bool, optional): whether to allow directories in
180                 the results or just files. Default False.
181 
182         Returns:
183             A list of matching files and/or directories, as locations
184             relative to our base_location.
185         """
186         location = self._normalize_slashes(location)
187         search_dir, pattern = os.path.split(location)
188         path = self.to_path(search_dir)
189 
190         if not os.path.isdir(path):
191             return []
192 
193         matches = [fn for fn in os.listdir(path) if fnmatch(fn, pattern + '*')]
194         out = []
195 
196         for match in matches:
197             matchpath = self.join(path, match)
198             if os.path.isdir(matchpath) and fnmatch(match, pattern):
199                 if maxdepth > 0:
200                     # exact directory match - walk down to maxdepth
201                     for root, dirs, files in os.walk(matchpath, topdown=True):
202                         depth = root[len(path):].count(os.path.sep)
203                         if depth == maxdepth:
204                             dirs[:] = []  # don't recurse any further
205 
206                         for fn in files + (dirs if include_dirs else []):
207                             out.append(self.to_location(self.join(root, fn)))
208 
209                 elif include_dirs:
210                     out.append(self.join(search_dir, match))
211 
212             elif (os.path.isfile(matchpath) and
213                   (fnmatch(match, pattern) or
214                    fnmatch(os.path.splitext(match)[0], pattern))):
215                 # exact filename match, or match up to an extension
216                 # note that we need fnmatch(match, pattern) in addition to the
217                 # splitext test to cover the case of the base filename itself
218                 # containing a dot.
219                 out.append(self.join(search_dir, match))
220 
221         return out
222 
223     def remove(self, filename):
224         """Delete a file or folder and prune the directory tree."""
225         path = self.to_path(filename)
226         if(os.path.isdir(path)):
227             shutil.rmtree(path)
228         else:
229             os.remove(path)
230 
231         filepath = os.path.split(path)[0]
232         try:
233             os.removedirs(filepath)
234         except OSError:
235             # directory was not empty - good that we're not removing it!
236             pass
237 
238     def remove_all(self, location):
239         """
240         Delete all files/directories in the dataset at this location.
241 
242         Afterward prunes the directory tree.
243         """
244         for fn in self.list(location):
245             self.remove(fn)
246 
247 
248 class FileWrapper:
249     def read(self, size=None):
250         raise NotImplementedError
251 
252     def readline(self, size=None):
253         raise NotImplementedError
254 
255     def __iter__(self):
256         return self
257 
258     def __next__(self):
259         line = self.readline()
260         if line:
261             return line
262         else:
263             raise StopIteration
264 
265     def write(self, s):
266         raise NotImplementedError
267 
268     def writelines(self, seq):
269         for s in seq:
270             self.write(s)
271
```
--- 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/qcodes/data/io.py b/qcodes/data/io.py
--- a/qcodes/data/io.py
+++ b/qcodes/data/io.py
@@ -28,13 +28,9 @@
     - iter(): usually return self, but can be any iterator over lines
     - next(): assuming iter() returns self, this yields the next line.
 
-    (note: iter and next can be constructed automatically by FileWrapper
-    if you implement readline.)
-
   In write or append mode:
     - write(s): add string s to the end of the file.
-    - writelines(seq): add a sequence of strings (can be constructed
-      automatically if you use FileWrapper)
+    - writelines(seq): add a sequence of strings
 
 IO managers should also implement:
 
@@ -223,7 +219,7 @@
     def remove(self, filename):
         """Delete a file or folder and prune the directory tree."""
         path = self.to_path(filename)
-        if(os.path.isdir(path)):
+        if os.path.isdir(path):
             shutil.rmtree(path)
         else:
             os.remove(path)
@@ -243,28 +239,3 @@
         """
         for fn in self.list(location):
             self.remove(fn)
-
-
-class FileWrapper:
-    def read(self, size=None):
-        raise NotImplementedError
-
-    def readline(self, size=None):
-        raise NotImplementedError
-
-    def __iter__(self):
-        return self
-
-    def __next__(self):
-        line = self.readline()
-        if line:
-            return line
-        else:
-            raise StopIteration
-
-    def write(self, s):
-        raise NotImplementedError
-
-    def writelines(self, seq):
-        for s in seq:
-            self.write(s)

{"golden_diff": "diff --git a/qcodes/data/io.py b/qcodes/data/io.py\n--- a/qcodes/data/io.py\n+++ b/qcodes/data/io.py\n@@ -28,13 +28,9 @@\n     - iter(): usually return self, but can be any iterator over lines\n     - next(): assuming iter() returns self, this yields the next line.\n \n-    (note: iter and next can be constructed automatically by FileWrapper\n-    if you implement readline.)\n-\n   In write or append mode:\n     - write(s): add string s to the end of the file.\n-    - writelines(seq): add a sequence of strings (can be constructed\n-      automatically if you use FileWrapper)\n+    - writelines(seq): add a sequence of strings\n \n IO managers should also implement:\n \n@@ -223,7 +219,7 @@\n     def remove(self, filename):\n         \"\"\"Delete a file or folder and prune the directory tree.\"\"\"\n         path = self.to_path(filename)\n-        if(os.path.isdir(path)):\n+        if os.path.isdir(path):\n             shutil.rmtree(path)\n         else:\n             os.remove(path)\n@@ -243,28 +239,3 @@\n         \"\"\"\n         for fn in self.list(location):\n             self.remove(fn)\n-\n-\n-class FileWrapper:\n-    def read(self, size=None):\n-        raise NotImplementedError\n-\n-    def readline(self, size=None):\n-        raise NotImplementedError\n-\n-    def __iter__(self):\n-        return self\n-\n-    def __next__(self):\n-        line = self.readline()\n-        if line:\n-            return line\n-        else:\n-            raise StopIteration\n-\n-    def write(self, s):\n-        raise NotImplementedError\n-\n-    def writelines(self, seq):\n-        for s in seq:\n-            self.write(s)\n", "issue": "Unused class FileWrapper\nIn the io manager module there is a FileWrapper class that seems to be never used anywhere?\r\nAside from the dubious utility of such a class (maybe if documented one could figure out) , maybe we should just remove it ?\r\n\r\n@QCoDeS/core  ? \r\n\n", "before_files": [{"content": "\"\"\"\nIO managers for QCodes.\n\nIO managers wrap whatever physical storage layer the user wants to use\nin an interface mimicking the built-in <open> context manager, with\nsome restrictions to minimize the overhead in creating new IO managers.\n\nThe main thing these managers need to implement is the open context manager:\n\n- Only the context manager needs to be implemented, not separate\n  open function and close methods.\n\n- open takes the standard parameters:\n\n    - filename: (string)\n    - mode: (string) only 'r' (read), 'w' (write), and 'a' (append) are\n      expected to be implemented. As with normal file objects, the only\n      difference between write and append is that write empties the file\n      before adding new data, and append leaves the existing contents in\n      place but starts writing at the end.\n    - encoding: If a special output encoding is desired. i.e. 'utf8\n\n- the file-like object returned should implement a minimal set of operations.\n\n  In read mode:\n    - read([size]): read to the end or at most size bytes into a string\n    - readline([size]): read until a newline or up to size bytes, into a string\n    - iter(): usually return self, but can be any iterator over lines\n    - next(): assuming iter() returns self, this yields the next line.\n\n    (note: iter and next can be constructed automatically by FileWrapper\n    if you implement readline.)\n\n  In write or append mode:\n    - write(s): add string s to the end of the file.\n    - writelines(seq): add a sequence of strings (can be constructed\n      automatically if you use FileWrapper)\n\nIO managers should also implement:\n\n- a join method, ala os.path.join(\\*args).\n- a list method, that returns all objects matching location\n- a remove method, ala os.remove(path) except that it will remove directories\n  as well as files, since we're allowing \"locations\" to be directories\n  or files.\n\"\"\"\n\nfrom contextlib import contextmanager\nimport os\nimport re\nimport shutil\nfrom fnmatch import fnmatch\n\nALLOWED_OPEN_MODES = ('r', 'w', 'a')\n\n\nclass DiskIO:\n\n    \"\"\"\n    Simple IO object to wrap disk operations with a custom base location.\n\n    Also accepts both forward and backward slashes at any point, and\n    normalizes both to the OS we are currently on.\n\n    Args:\n        base_location (str): a path to the root data folder.\n            Converted to an absolute path immediately, so even if you supply a\n            relative path, later changes to the OS working directory will not\n            affect data paths.\n    \"\"\"\n\n    def __init__(self, base_location):\n        if base_location is None:\n            self.base_location = None\n        else:\n            base_location = self._normalize_slashes(base_location)\n            self.base_location = os.path.abspath(base_location)\n\n    @contextmanager\n    def open(self, filename, mode, encoding=None):\n        \"\"\"\n        Mimic the interface of the built in open context manager.\n\n        Args:\n            filename (str): path relative to base_location.\n\n            mode (str): 'r' (read), 'w' (write), or 'a' (append).\n                Other open modes are not supported because we don't want\n                to force all IO managers to support others.\n\n        Returns:\n            context manager yielding the open file\n        \"\"\"\n        if mode not in ALLOWED_OPEN_MODES:\n            raise ValueError('mode {} not allowed in IO managers'.format(mode))\n\n        filepath = self.to_path(filename)\n\n        # make directories if needed\n        dirpath = os.path.dirname(filepath)\n        if not os.path.exists(dirpath):\n            os.makedirs(dirpath)\n\n        # normally we'd construct this context manager with try/finally, but\n        # here we already have a context manager for open so we just wrap it\n        with open(filepath, mode, encoding=encoding) as f:\n            yield f\n\n    def _normalize_slashes(self, location):\n        # note that this is NOT os.path.join - the difference is os.path.join\n        # discards empty strings, so if you use it on a re.split absolute\n        # path you will get a relative path!\n        return os.sep.join(re.split('[\\\\\\\\/]', location))\n\n    def to_path(self, location):\n        \"\"\"\n        Convert a location string into a path on the local file system.\n\n        For DiskIO this just fixes slashes and prepends the base location,\n        doing nothing active with the file. But for other io managers that\n        refer to remote storage, this method may actually fetch the file and\n        put it at a temporary local path.\n\n        Args:\n            location (str): A location string for a complete dataset or\n                a file within it.\n\n        Returns:\n            path (str): The path on disk to which this location maps.\n        \"\"\"\n        location = self._normalize_slashes(location)\n        if self.base_location:\n            return os.path.join(self.base_location, location)\n        else:\n            return location\n\n    def to_location(self, path):\n        \"\"\"\n        Convert a local filesystem path into a location string.\n\n        Args:\n            path (str): a path on the local file system.\n\n        Returns:\n            location (str): the location string corresponding to this path.\n        \"\"\"\n        if self.base_location:\n            return os.path.relpath(path, self.base_location)\n        else:\n            return path\n\n    def __repr__(self):\n        \"\"\"Show the base location in the repr.\"\"\"\n        return '<DiskIO, base_location={}>'.format(repr(self.base_location))\n\n    def join(self, *args):\n        \"\"\"Context-dependent os.path.join for this io manager.\"\"\"\n        return os.path.join(*list(map(self._normalize_slashes, args)))\n\n    def isfile(self, location):\n        \"\"\"Check whether this location matches a file.\"\"\"\n        path = self.to_path(location)\n        return os.path.isfile(path)\n\n    def list(self, location, maxdepth=1, include_dirs=False):\n        \"\"\"\n        Return all files that match location.\n\n        This is either files whose names match up to an arbitrary extension,\n        or any files within an exactly matching directory name.\n\n        Args:\n            location (str): the location to match.\n                May contain the usual path wildcards * and ?\n\n            maxdepth (int, optional): maximum levels of directory nesting to\n                recurse into looking for files. Default 1.\n\n            include_dirs (bool, optional): whether to allow directories in\n                the results or just files. Default False.\n\n        Returns:\n            A list of matching files and/or directories, as locations\n            relative to our base_location.\n        \"\"\"\n        location = self._normalize_slashes(location)\n        search_dir, pattern = os.path.split(location)\n        path = self.to_path(search_dir)\n\n        if not os.path.isdir(path):\n            return []\n\n        matches = [fn for fn in os.listdir(path) if fnmatch(fn, pattern + '*')]\n        out = []\n\n        for match in matches:\n            matchpath = self.join(path, match)\n            if os.path.isdir(matchpath) and fnmatch(match, pattern):\n                if maxdepth > 0:\n                    # exact directory match - walk down to maxdepth\n                    for root, dirs, files in os.walk(matchpath, topdown=True):\n                        depth = root[len(path):].count(os.path.sep)\n                        if depth == maxdepth:\n                            dirs[:] = []  # don't recurse any further\n\n                        for fn in files + (dirs if include_dirs else []):\n                            out.append(self.to_location(self.join(root, fn)))\n\n                elif include_dirs:\n                    out.append(self.join(search_dir, match))\n\n            elif (os.path.isfile(matchpath) and\n                  (fnmatch(match, pattern) or\n                   fnmatch(os.path.splitext(match)[0], pattern))):\n                # exact filename match, or match up to an extension\n                # note that we need fnmatch(match, pattern) in addition to the\n                # splitext test to cover the case of the base filename itself\n                # containing a dot.\n                out.append(self.join(search_dir, match))\n\n        return out\n\n    def remove(self, filename):\n        \"\"\"Delete a file or folder and prune the directory tree.\"\"\"\n        path = self.to_path(filename)\n        if(os.path.isdir(path)):\n            shutil.rmtree(path)\n        else:\n            os.remove(path)\n\n        filepath = os.path.split(path)[0]\n        try:\n            os.removedirs(filepath)\n        except OSError:\n            # directory was not empty - good that we're not removing it!\n            pass\n\n    def remove_all(self, location):\n        \"\"\"\n        Delete all files/directories in the dataset at this location.\n\n        Afterward prunes the directory tree.\n        \"\"\"\n        for fn in self.list(location):\n            self.remove(fn)\n\n\nclass FileWrapper:\n    def read(self, size=None):\n        raise NotImplementedError\n\n    def readline(self, size=None):\n        raise NotImplementedError\n\n    def __iter__(self):\n        return self\n\n    def __next__(self):\n        line = self.readline()\n        if line:\n            return line\n        else:\n            raise StopIteration\n\n    def write(self, s):\n        raise NotImplementedError\n\n    def writelines(self, seq):\n        for s in seq:\n            self.write(s)\n", "path": "qcodes/data/io.py"}], "after_files": [{"content": "\"\"\"\nIO managers for QCodes.\n\nIO managers wrap whatever physical storage layer the user wants to use\nin an interface mimicking the built-in <open> context manager, with\nsome restrictions to minimize the overhead in creating new IO managers.\n\nThe main thing these managers need to implement is the open context manager:\n\n- Only the context manager needs to be implemented, not separate\n  open function and close methods.\n\n- open takes the standard parameters:\n\n    - filename: (string)\n    - mode: (string) only 'r' (read), 'w' (write), and 'a' (append) are\n      expected to be implemented. As with normal file objects, the only\n      difference between write and append is that write empties the file\n      before adding new data, and append leaves the existing contents in\n      place but starts writing at the end.\n    - encoding: If a special output encoding is desired. i.e. 'utf8\n\n- the file-like object returned should implement a minimal set of operations.\n\n  In read mode:\n    - read([size]): read to the end or at most size bytes into a string\n    - readline([size]): read until a newline or up to size bytes, into a string\n    - iter(): usually return self, but can be any iterator over lines\n    - next(): assuming iter() returns self, this yields the next line.\n\n  In write or append mode:\n    - write(s): add string s to the end of the file.\n    - writelines(seq): add a sequence of strings\n\nIO managers should also implement:\n\n- a join method, ala os.path.join(\\*args).\n- a list method, that returns all objects matching location\n- a remove method, ala os.remove(path) except that it will remove directories\n  as well as files, since we're allowing \"locations\" to be directories\n  or files.\n\"\"\"\n\nfrom contextlib import contextmanager\nimport os\nimport re\nimport shutil\nfrom fnmatch import fnmatch\n\nALLOWED_OPEN_MODES = ('r', 'w', 'a')\n\n\nclass DiskIO:\n\n    \"\"\"\n    Simple IO object to wrap disk operations with a custom base location.\n\n    Also accepts both forward and backward slashes at any point, and\n    normalizes both to the OS we are currently on.\n\n    Args:\n        base_location (str): a path to the root data folder.\n            Converted to an absolute path immediately, so even if you supply a\n            relative path, later changes to the OS working directory will not\n            affect data paths.\n    \"\"\"\n\n    def __init__(self, base_location):\n        if base_location is None:\n            self.base_location = None\n        else:\n            base_location = self._normalize_slashes(base_location)\n            self.base_location = os.path.abspath(base_location)\n\n    @contextmanager\n    def open(self, filename, mode, encoding=None):\n        \"\"\"\n        Mimic the interface of the built in open context manager.\n\n        Args:\n            filename (str): path relative to base_location.\n\n            mode (str): 'r' (read), 'w' (write), or 'a' (append).\n                Other open modes are not supported because we don't want\n                to force all IO managers to support others.\n\n        Returns:\n            context manager yielding the open file\n        \"\"\"\n        if mode not in ALLOWED_OPEN_MODES:\n            raise ValueError('mode {} not allowed in IO managers'.format(mode))\n\n        filepath = self.to_path(filename)\n\n        # make directories if needed\n        dirpath = os.path.dirname(filepath)\n        if not os.path.exists(dirpath):\n            os.makedirs(dirpath)\n\n        # normally we'd construct this context manager with try/finally, but\n        # here we already have a context manager for open so we just wrap it\n        with open(filepath, mode, encoding=encoding) as f:\n            yield f\n\n    def _normalize_slashes(self, location):\n        # note that this is NOT os.path.join - the difference is os.path.join\n        # discards empty strings, so if you use it on a re.split absolute\n        # path you will get a relative path!\n        return os.sep.join(re.split('[\\\\\\\\/]', location))\n\n    def to_path(self, location):\n        \"\"\"\n        Convert a location string into a path on the local file system.\n\n        For DiskIO this just fixes slashes and prepends the base location,\n        doing nothing active with the file. But for other io managers that\n        refer to remote storage, this method may actually fetch the file and\n        put it at a temporary local path.\n\n        Args:\n            location (str): A location string for a complete dataset or\n                a file within it.\n\n        Returns:\n            path (str): The path on disk to which this location maps.\n        \"\"\"\n        location = self._normalize_slashes(location)\n        if self.base_location:\n            return os.path.join(self.base_location, location)\n        else:\n            return location\n\n    def to_location(self, path):\n        \"\"\"\n        Convert a local filesystem path into a location string.\n\n        Args:\n            path (str): a path on the local file system.\n\n        Returns:\n            location (str): the location string corresponding to this path.\n        \"\"\"\n        if self.base_location:\n            return os.path.relpath(path, self.base_location)\n        else:\n            return path\n\n    def __repr__(self):\n        \"\"\"Show the base location in the repr.\"\"\"\n        return '<DiskIO, base_location={}>'.format(repr(self.base_location))\n\n    def join(self, *args):\n        \"\"\"Context-dependent os.path.join for this io manager.\"\"\"\n        return os.path.join(*list(map(self._normalize_slashes, args)))\n\n    def isfile(self, location):\n        \"\"\"Check whether this location matches a file.\"\"\"\n        path = self.to_path(location)\n        return os.path.isfile(path)\n\n    def list(self, location, maxdepth=1, include_dirs=False):\n        \"\"\"\n        Return all files that match location.\n\n        This is either files whose names match up to an arbitrary extension,\n        or any files within an exactly matching directory name.\n\n        Args:\n            location (str): the location to match.\n                May contain the usual path wildcards * and ?\n\n            maxdepth (int, optional): maximum levels of directory nesting to\n                recurse into looking for files. Default 1.\n\n            include_dirs (bool, optional): whether to allow directories in\n                the results or just files. Default False.\n\n        Returns:\n            A list of matching files and/or directories, as locations\n            relative to our base_location.\n        \"\"\"\n        location = self._normalize_slashes(location)\n        search_dir, pattern = os.path.split(location)\n        path = self.to_path(search_dir)\n\n        if not os.path.isdir(path):\n            return []\n\n        matches = [fn for fn in os.listdir(path) if fnmatch(fn, pattern + '*')]\n        out = []\n\n        for match in matches:\n            matchpath = self.join(path, match)\n            if os.path.isdir(matchpath) and fnmatch(match, pattern):\n                if maxdepth > 0:\n                    # exact directory match - walk down to maxdepth\n                    for root, dirs, files in os.walk(matchpath, topdown=True):\n                        depth = root[len(path):].count(os.path.sep)\n                        if depth == maxdepth:\n                            dirs[:] = []  # don't recurse any further\n\n                        for fn in files + (dirs if include_dirs else []):\n                            out.append(self.to_location(self.join(root, fn)))\n\n                elif include_dirs:\n                    out.append(self.join(search_dir, match))\n\n            elif (os.path.isfile(matchpath) and\n                  (fnmatch(match, pattern) or\n                   fnmatch(os.path.splitext(match)[0], pattern))):\n                # exact filename match, or match up to an extension\n                # note that we need fnmatch(match, pattern) in addition to the\n                # splitext test to cover the case of the base filename itself\n                # containing a dot.\n                out.append(self.join(search_dir, match))\n\n        return out\n\n    def remove(self, filename):\n        \"\"\"Delete a file or folder and prune the directory tree.\"\"\"\n        path = self.to_path(filename)\n        if os.path.isdir(path):\n            shutil.rmtree(path)\n        else:\n            os.remove(path)\n\n        filepath = os.path.split(path)[0]\n        try:\n            os.removedirs(filepath)\n        except OSError:\n            # directory was not empty - good that we're not removing it!\n            pass\n\n    def remove_all(self, location):\n        \"\"\"\n        Delete all files/directories in the dataset at this location.\n\n        Afterward prunes the directory tree.\n        \"\"\"\n        for fn in self.list(location):\n            self.remove(fn)\n", "path": "qcodes/data/io.py"}]}