We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
DiskIO discards absolute path information
``` python
> my_io = qcodes.DiskIO('/home/eendebakpt/tmp')
> print(my_io)
<DiskIO, base_location=/mounts/d3/home/eendebakpt/svn/qtt/home/eendebakpt/tmp>
```

The DiskIO object converts my absolute path to a relative path. The problem is in `def _normalize_slashes(self, location)` from `qcodes/data/io.py`.  
I am not sure about what `_normalize_slashes` should do, so I am not sure how to fix this


--- 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 - Only the context manager needs to be implemented, not separate
10   open function and close methods.
11 
12 - open takes the standard parameters:
13     filename: (string)
14     mode: (string) only 'r' (read), 'w' (write), and 'a' (append) are
15         expected to be implemented. As with normal file objects, the only
16         difference between write and append is that write empties the file
17         before adding new data, and append leaves the existing contents in
18         place but starts writing at the end.
19 
20 - the file-like object returned should implement a minimal set of operations.
21 
22   In read mode:
23     read([size]): read to the end or at most size bytes into a string
24     readline([size]): read until a newline or up to size bytes, into a string
25     iter(): usually return self, but can be any iterator over lines
26     next(): assuming iter() returns self, this yields the next line.
27     (note: iter and next can be constructed automatically by FileWrapper
28      if you implement readline.)
29 
30   In write or append mode:
31     write(s): add string s to the end of the file.
32     writelines(seq): add a sequence of strings (can be constructed
33         automatically if you use FileWrapper)
34 
35 IO managers should also implement:
36 - a join method, ala os.path.join(*args).
37 - a list method, that returns all objects matching location
38 - a remove method, ala os.remove(path) except that it will remove directories
39     as well as files, since we're allowing "locations" to be directories
40     or files.
41 '''
42 
43 from contextlib import contextmanager
44 import os
45 import re
46 import shutil
47 
48 ALLOWED_OPEN_MODES = ('r', 'w', 'a')
49 
50 
51 class DiskIO:
52     '''
53     Simple IO object to wrap disk operations with a custom base location
54 
55     Also accepts both forward and backward slashes at any point, and
56     normalizes both to the OS we are currently on
57     '''
58     def __init__(self, base_location):
59         base_location = self._normalize_slashes(base_location)
60         self.base_location = os.path.abspath(base_location)
61 
62     @contextmanager
63     def open(self, filename, mode):
64         '''
65         mimics the interface of the built in open context manager
66         filename: string, relative to base_location
67         mode: 'r' (read), 'w' (write), or 'a' (append)
68             other open modes are not supported because we don't want
69             to force all IO managers to support others.
70         '''
71         if mode not in ALLOWED_OPEN_MODES:
72             raise ValueError('mode {} not allowed in IO managers'.format(mode))
73 
74         filepath = self._add_base(filename)
75 
76         # make directories if needed
77         dirpath = os.path.dirname(filepath)
78         if not os.path.exists(dirpath):
79             os.makedirs(dirpath)
80 
81         # normally we'd construct this context manager with try/finally, but
82         # here we already have a context manager for open so we just wrap it
83         with open(filepath, mode) as f:
84             yield f
85 
86     def _normalize_slashes(self, location):
87         return os.path.join(*re.split('[\\\\/]', location))
88 
89     def _add_base(self, location):
90         location = self._normalize_slashes(location)
91         return os.path.join(self.base_location, location)
92 
93     def _strip_base(self, path):
94         return os.path.relpath(path, self.base_location)
95 
96     def __repr__(self):
97         return '<DiskIO, base_location={}>'.format(self.base_location)
98 
99     def join(self, *args):
100         '''
101         the context-dependent version of os.path.join for this io manager
102         '''
103         return os.path.join(*args)
104 
105     def isfile(self, location):
106         '''
107         does `location` match a file?
108         '''
109         path = self._add_base(location)
110         return os.path.isfile(path)
111 
112     def list(self, location, maxdepth=1):
113         '''
114         return all files that match location, either files
115         whose names match up to an arbitrary extension
116         or any files within an exactly matching directory name,
117         nested as far as maxdepth (default 1) levels
118         '''
119         location = self._normalize_slashes(location)
120         base_location, pattern = os.path.split(location)
121         path = self._add_base(base_location)
122 
123         if not os.path.isdir(path):
124             return []
125 
126         matches = [fn for fn in os.listdir(path) if fn.startswith(pattern)]
127         out = []
128 
129         for match in matches:
130             matchpath = self.join(path, match)
131             if os.path.isdir(matchpath) and match == pattern and maxdepth > 0:
132                 # exact directory match - walk down to maxdepth
133                 for root, dirs, files in os.walk(matchpath, topdown=True):
134                     depth = root[len(path):].count(os.path.sep)
135                     if depth == maxdepth:
136                         dirs[:] = []  # don't recurse any further
137                     for fn in files:
138                         out.append(self._strip_base(self.join(root, fn)))
139 
140             elif (os.path.isfile(matchpath) and
141                   (match == pattern or os.path.splitext(match)[0] == pattern)):
142                 # exact filename match, or match up to an extension
143                 # note that we need match == pattern in addition to the
144                 # splitext test to cover the case of the base filename itself
145                 # containing a dot.
146                 out.append(self.join(base_location, match))
147 
148         return out
149 
150     def remove(self, filename):
151         '''
152         delete this file/folder and prune the directory tree
153         '''
154         path = self._add_base(filename)
155         if(os.path.isdir(path)):
156             shutil.rmtree(path)
157         else:
158             os.remove(path)
159 
160         filepath = os.path.split(path)[0]
161         try:
162             os.removedirs(filepath)
163         except OSError:
164             # directory was not empty - good that we're not removing it!
165             pass
166 
167     def remove_all(self, location):
168         '''
169         delete all files/directories in the dataset at this location,
170         and prune the directory tree
171         '''
172         for fn in self.list(location):
173             self.remove(fn)
174 
175 
176 class FileWrapper:
177     def read(self, size=None):
178         raise NotImplementedError
179 
180     def readline(self, size=None):
181         raise NotImplementedError
182 
183     def __iter__(self):
184         return self
185 
186     def __next__(self):
187         line = self.readline()
188         if line:
189             return line
190         else:
191             raise StopIteration
192 
193     def write(self, s):
194         raise NotImplementedError
195 
196     def writelines(self, seq):
197         for s in seq:
198             self.write(s)
199
```
--- 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
@@ -84,7 +84,10 @@
             yield f
 
     def _normalize_slashes(self, location):
-        return os.path.join(*re.split('[\\\\/]', location))
+        # note that this is NOT os.path.join - the difference is os.path.join
+        # discards empty strings, so if you use it on a re.split absolute
+        # path you will get a relative path!
+        return os.sep.join(re.split('[\\\\/]', location))
 
     def _add_base(self, location):
         location = self._normalize_slashes(location)

{"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@@ -84,7 +84,10 @@\n             yield f\n \n     def _normalize_slashes(self, location):\n-        return os.path.join(*re.split('[\\\\\\\\/]', 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 _add_base(self, location):\n         location = self._normalize_slashes(location)\n", "issue": "DiskIO discards absolute path information\n``` python\n> my_io = qcodes.DiskIO('/home/eendebakpt/tmp')\n> print(my_io)\n<DiskIO, base_location=/mounts/d3/home/eendebakpt/svn/qtt/home/eendebakpt/tmp>\n```\n\nThe DiskIO object converts my absolute path to a relative path. The problem is in `def _normalize_slashes(self, location)` from `qcodes/data/io.py`.  \nI am not sure about what `_normalize_slashes` should do, so I am not sure how to fix this\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- Only the context manager needs to be implemented, not separate\n  open function and close methods.\n\n- open takes the standard parameters:\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\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    (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- 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\n\nALLOWED_OPEN_MODES = ('r', 'w', 'a')\n\n\nclass DiskIO:\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    def __init__(self, base_location):\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):\n        '''\n        mimics the interface of the built in open context manager\n        filename: string, relative to base_location\n        mode: '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        if mode not in ALLOWED_OPEN_MODES:\n            raise ValueError('mode {} not allowed in IO managers'.format(mode))\n\n        filepath = self._add_base(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) as f:\n            yield f\n\n    def _normalize_slashes(self, location):\n        return os.path.join(*re.split('[\\\\\\\\/]', location))\n\n    def _add_base(self, location):\n        location = self._normalize_slashes(location)\n        return os.path.join(self.base_location, location)\n\n    def _strip_base(self, path):\n        return os.path.relpath(path, self.base_location)\n\n    def __repr__(self):\n        return '<DiskIO, base_location={}>'.format(self.base_location)\n\n    def join(self, *args):\n        '''\n        the context-dependent version of os.path.join for this io manager\n        '''\n        return os.path.join(*args)\n\n    def isfile(self, location):\n        '''\n        does `location` match a file?\n        '''\n        path = self._add_base(location)\n        return os.path.isfile(path)\n\n    def list(self, location, maxdepth=1):\n        '''\n        return all files that match location, either files\n        whose names match up to an arbitrary extension\n        or any files within an exactly matching directory name,\n        nested as far as maxdepth (default 1) levels\n        '''\n        location = self._normalize_slashes(location)\n        base_location, pattern = os.path.split(location)\n        path = self._add_base(base_location)\n\n        if not os.path.isdir(path):\n            return []\n\n        matches = [fn for fn in os.listdir(path) if fn.startswith(pattern)]\n        out = []\n\n        for match in matches:\n            matchpath = self.join(path, match)\n            if os.path.isdir(matchpath) and match == pattern and 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                    for fn in files:\n                        out.append(self._strip_base(self.join(root, fn)))\n\n            elif (os.path.isfile(matchpath) and\n                  (match == pattern or os.path.splitext(match)[0] == pattern)):\n                # exact filename match, or match up to an extension\n                # note that we need 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(base_location, match))\n\n        return out\n\n    def remove(self, filename):\n        '''\n        delete this file/folder and prune the directory tree\n        '''\n        path = self._add_base(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        and prune 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- Only the context manager needs to be implemented, not separate\n  open function and close methods.\n\n- open takes the standard parameters:\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\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    (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- 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\n\nALLOWED_OPEN_MODES = ('r', 'w', 'a')\n\n\nclass DiskIO:\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    def __init__(self, base_location):\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):\n        '''\n        mimics the interface of the built in open context manager\n        filename: string, relative to base_location\n        mode: '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        if mode not in ALLOWED_OPEN_MODES:\n            raise ValueError('mode {} not allowed in IO managers'.format(mode))\n\n        filepath = self._add_base(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) 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 _add_base(self, location):\n        location = self._normalize_slashes(location)\n        return os.path.join(self.base_location, location)\n\n    def _strip_base(self, path):\n        return os.path.relpath(path, self.base_location)\n\n    def __repr__(self):\n        return '<DiskIO, base_location={}>'.format(self.base_location)\n\n    def join(self, *args):\n        '''\n        the context-dependent version of os.path.join for this io manager\n        '''\n        return os.path.join(*args)\n\n    def isfile(self, location):\n        '''\n        does `location` match a file?\n        '''\n        path = self._add_base(location)\n        return os.path.isfile(path)\n\n    def list(self, location, maxdepth=1):\n        '''\n        return all files that match location, either files\n        whose names match up to an arbitrary extension\n        or any files within an exactly matching directory name,\n        nested as far as maxdepth (default 1) levels\n        '''\n        location = self._normalize_slashes(location)\n        base_location, pattern = os.path.split(location)\n        path = self._add_base(base_location)\n\n        if not os.path.isdir(path):\n            return []\n\n        matches = [fn for fn in os.listdir(path) if fn.startswith(pattern)]\n        out = []\n\n        for match in matches:\n            matchpath = self.join(path, match)\n            if os.path.isdir(matchpath) and match == pattern and 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                    for fn in files:\n                        out.append(self._strip_base(self.join(root, fn)))\n\n            elif (os.path.isfile(matchpath) and\n                  (match == pattern or os.path.splitext(match)[0] == pattern)):\n                # exact filename match, or match up to an extension\n                # note that we need 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(base_location, match))\n\n        return out\n\n    def remove(self, filename):\n        '''\n        delete this file/folder and prune the directory tree\n        '''\n        path = self._add_base(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        and prune 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"}]}