We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
bug on luigi.contrib.ftp.AtomicFtpfile
on luigi.contrib.ftp.AtomicFtpfile, self.path is accessed before being set.

```
luigi/contrib/ftp.py Line 170 Character 26
167:    """
168:    
169:    def __init__(self, fs, path):
170:    self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)
    Access to member 'path' before its definition line 172
171:    self._fs = fs
172:    self.path = path
173:    super(AtomicFtpfile, self).__init__(self.__tmp_path, 'w')
```

captured by [landscape.io](https://landscape.io/github/steenzout/luigi/4/messages/error)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `luigi/contrib/ftp.py`
Content:
```
1 """
2 This library is a wrapper of ftplib.
3 It is convenient to move data from/to FTP.
4 
5 There is an example on how to use it (example/ftp_experiment_outputs.py)
6 
7 You can also find unittest for each class.
8 
9 Be aware that normal ftp do not provide secure communication.
10 """
11 import datetime
12 import os
13 import random
14 import ftplib
15 import luigi
16 import luigi.target
17 import luigi.format
18 from luigi.format import FileWrapper
19 
20 
21 class RemoteFileSystem(luigi.target.FileSystem):
22 
23     def __init__(self, host, username=None, password=None, port=21, tls=False):
24         self.host = host
25         self.username = username
26         self.password = password
27         self.port = port
28         self.tls = tls
29 
30     def _connect(self):
31         """
32         Log in to ftp.
33         """
34         if self.tls:
35             self.ftpcon = ftplib.FTP_TLS()
36         else:
37             self.ftpcon = ftplib.FTP()
38         self.ftpcon.connect(self.host, self.port)
39         self.ftpcon.login(self.username, self.password)
40         if self.tls:
41             self.ftpcon.prot_p()
42 
43     def exists(self, path, mtime=None):
44         """
45         Return `True` if file or directory at `path` exist, False otherwise.
46 
47         Additional check on modified time when mtime is passed in.
48 
49         Return False if the file's modified time is older mtime.
50         """
51         self._connect()
52         files = self.ftpcon.nlst(path)
53 
54         result = False
55         if files:
56             if mtime:
57                 mdtm = self.ftpcon.sendcmd('MDTM ' + path)
58                 modified = datetime.datetime.strptime(mdtm[4:], "%Y%m%d%H%M%S")
59                 result = modified > mtime
60             else:
61                 result = True
62 
63         self.ftpcon.quit()
64 
65         return result
66 
67     def _rm_recursive(self, ftp, path):
68         """
69         Recursively delete a directory tree on a remote server.
70 
71         Source: https://gist.github.com/artlogic/2632647
72         """
73         wd = ftp.pwd()
74 
75         try:
76             names = ftp.nlst(path)
77         except ftplib.all_errors as e:
78             # some FTP servers complain when you try and list non-existent paths
79             return
80 
81         for name in names:
82             if os.path.split(name)[1] in ('.', '..'):
83                 continue
84 
85             try:
86                 ftp.cwd(name)  # if we can cwd to it, it's a folder
87                 ftp.cwd(wd)  # don't try a nuke a folder we're in
88                 self._rm_recursive(ftp, name)
89             except ftplib.all_errors:
90                 ftp.delete(name)
91 
92         try:
93             ftp.rmd(path)
94         except ftplib.all_errors as e:
95             print('_rm_recursive: Could not remove {0}: {1}'.format(path, e))
96 
97     def remove(self, path, recursive=True):
98         """
99         Remove file or directory at location ``path``.
100 
101         :param path: a path within the FileSystem to remove.
102         :type path: str
103         :param recursive: if the path is a directory, recursively remove the directory and
104                           all of its descendants. Defaults to ``True``.
105         :type recursive: bool
106         """
107         self._connect()
108 
109         if recursive:
110             self._rm_recursive(self.ftpcon, path)
111         else:
112             try:
113                 # try delete file
114                 self.ftpcon.delete(path)
115             except ftplib.all_errors:
116                 # it is a folder, delete it
117                 self.ftpcon.rmd(path)
118 
119         self.ftpcon.quit()
120 
121     def put(self, local_path, path):
122         # create parent folder if not exists
123         self._connect()
124 
125         normpath = os.path.normpath(path)
126         folder = os.path.dirname(normpath)
127 
128         # create paths if do not exists
129         for subfolder in folder.split(os.sep):
130             if subfolder and subfolder not in self.ftpcon.nlst():
131                 self.ftpcon.mkd(subfolder)
132 
133             self.ftpcon.cwd(subfolder)
134 
135         # go back to ftp root folder
136         self.ftpcon.cwd("/")
137 
138         # random file name
139         tmp_path = folder + os.sep + 'luigi-tmp-%09d' % random.randrange(0, 1e10)
140 
141         self.ftpcon.storbinary('STOR %s' % tmp_path, open(local_path, 'rb'))
142         self.ftpcon.rename(tmp_path, normpath)
143 
144         self.ftpcon.quit()
145 
146     def get(self, path, local_path):
147         # Create folder if it does not exist
148         normpath = os.path.normpath(local_path)
149         folder = os.path.dirname(normpath)
150         if folder and not os.path.exists(folder):
151             os.makedirs(folder)
152 
153         tmp_local_path = local_path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)
154         # download file
155         self._connect()
156         self.ftpcon.retrbinary('RETR %s' % path, open(tmp_local_path, 'wb').write)
157         self.ftpcon.quit()
158 
159         os.rename(tmp_local_path, local_path)
160 
161 
162 class AtomicFtpfile(file):
163     """
164     Simple class that writes to a temp file and upload to ftp on close().
165 
166     Also cleans up the temp file if close is not invoked.
167     """
168 
169     def __init__(self, fs, path):
170         self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)
171         self._fs = fs
172         self.path = path
173         super(AtomicFtpfile, self).__init__(self.__tmp_path, 'w')
174 
175     def close(self):
176         # close and upload file to ftp
177         super(AtomicFtpfile, self).close()
178         self._fs.put(self.__tmp_path, self.path)
179         os.remove(self.__tmp_path)
180 
181     def __del__(self):
182         if os.path.exists(self.__tmp_path):
183             os.remove(self.__tmp_path)
184 
185     @property
186     def tmp_path(self):
187         return self.__tmp_path
188 
189     @property
190     def fs(self):
191         return self._fs
192 
193     def __exit__(self, exc_type, exc, traceback):
194         """
195         Close/commit the file if there are no exception
196 
197         Upload file to ftp
198         """
199         if exc_type:
200             return
201         return file.__exit__(self, exc_type, exc, traceback)
202 
203 
204 class RemoteTarget(luigi.target.FileSystemTarget):
205     """
206     Target used for reading from remote files.
207 
208     The target is implemented using ssh commands streaming data over the network.
209     """
210 
211     def __init__(self, path, host, format=None, username=None, password=None, port=21, mtime=None, tls=False):
212         self.path = path
213         self.mtime = mtime
214         self.format = format
215         self.tls = tls
216         self._fs = RemoteFileSystem(host, username, password, port, tls)
217 
218     @property
219     def fs(self):
220         return self._fs
221 
222     def open(self, mode):
223         """
224         Open the FileSystem target.
225 
226         This method returns a file-like object which can either be read from or written to depending
227         on the specified mode.
228 
229         :param mode: the mode `r` opens the FileSystemTarget in read-only mode, whereas `w` will
230                      open the FileSystemTarget in write mode. Subclasses can implement
231                      additional options.
232         :type mode: str
233         """
234         if mode == 'w':
235             if self.format:
236                 return self.format.pipe_writer(AtomicFtpfile(self._fs, self.path))
237             else:
238                 return AtomicFtpfile(self._fs, self.path)
239 
240         elif mode == 'r':
241             self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)
242             # download file to local
243             self._fs.get(self.path, self.__tmp_path)
244 
245             # manage tmp file
246             fileobj = FileWrapper(open(self.__tmp_path, 'r'))
247             if self.format:
248                 return self.format.pipe_reader(fileobj)
249             return fileobj
250         else:
251             raise Exception('mode must be r/w')
252 
253     def exists(self):
254         return self.fs.exists(self.path, self.mtime)
255 
256     def put(self, local_path):
257         self.fs.put(local_path, self.path)
258 
259     def get(self, local_path):
260         self.fs.get(self.path, local_path)
261
```
--- 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/luigi/contrib/ftp.py b/luigi/contrib/ftp.py
--- a/luigi/contrib/ftp.py
+++ b/luigi/contrib/ftp.py
@@ -167,7 +167,14 @@
     """
 
     def __init__(self, fs, path):
-        self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)
+        """
+        Initializes an AtomicFtpfile instance.
+
+        :param fs:
+        :param path:
+        :type path: str
+        """
+        self.__tmp_path = '%s-luigi-tmp-%09d' % (path, random.randrange(0, 1e10))
         self._fs = fs
         self.path = path
         super(AtomicFtpfile, self).__init__(self.__tmp_path, 'w')

{"golden_diff": "diff --git a/luigi/contrib/ftp.py b/luigi/contrib/ftp.py\n--- a/luigi/contrib/ftp.py\n+++ b/luigi/contrib/ftp.py\n@@ -167,7 +167,14 @@\n     \"\"\"\n \n     def __init__(self, fs, path):\n-        self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)\n+        \"\"\"\n+        Initializes an AtomicFtpfile instance.\n+\n+        :param fs:\n+        :param path:\n+        :type path: str\n+        \"\"\"\n+        self.__tmp_path = '%s-luigi-tmp-%09d' % (path, random.randrange(0, 1e10))\n         self._fs = fs\n         self.path = path\n         super(AtomicFtpfile, self).__init__(self.__tmp_path, 'w')\n", "issue": "bug on luigi.contrib.ftp.AtomicFtpfile\non luigi.contrib.ftp.AtomicFtpfile, self.path is accessed before being set.\n\n```\nluigi/contrib/ftp.py Line 170 Character 26\n167:    \"\"\"\n168:    \n169:    def __init__(self, fs, path):\n170:    self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)\n    Access to member 'path' before its definition line 172\n171:    self._fs = fs\n172:    self.path = path\n173:    super(AtomicFtpfile, self).__init__(self.__tmp_path, 'w')\n```\n\ncaptured by [landscape.io](https://landscape.io/github/steenzout/luigi/4/messages/error)\n\n", "before_files": [{"content": "\"\"\"\nThis library is a wrapper of ftplib.\nIt is convenient to move data from/to FTP.\n\nThere is an example on how to use it (example/ftp_experiment_outputs.py)\n\nYou can also find unittest for each class.\n\nBe aware that normal ftp do not provide secure communication.\n\"\"\"\nimport datetime\nimport os\nimport random\nimport ftplib\nimport luigi\nimport luigi.target\nimport luigi.format\nfrom luigi.format import FileWrapper\n\n\nclass RemoteFileSystem(luigi.target.FileSystem):\n\n    def __init__(self, host, username=None, password=None, port=21, tls=False):\n        self.host = host\n        self.username = username\n        self.password = password\n        self.port = port\n        self.tls = tls\n\n    def _connect(self):\n        \"\"\"\n        Log in to ftp.\n        \"\"\"\n        if self.tls:\n            self.ftpcon = ftplib.FTP_TLS()\n        else:\n            self.ftpcon = ftplib.FTP()\n        self.ftpcon.connect(self.host, self.port)\n        self.ftpcon.login(self.username, self.password)\n        if self.tls:\n            self.ftpcon.prot_p()\n\n    def exists(self, path, mtime=None):\n        \"\"\"\n        Return `True` if file or directory at `path` exist, False otherwise.\n\n        Additional check on modified time when mtime is passed in.\n\n        Return False if the file's modified time is older mtime.\n        \"\"\"\n        self._connect()\n        files = self.ftpcon.nlst(path)\n\n        result = False\n        if files:\n            if mtime:\n                mdtm = self.ftpcon.sendcmd('MDTM ' + path)\n                modified = datetime.datetime.strptime(mdtm[4:], \"%Y%m%d%H%M%S\")\n                result = modified > mtime\n            else:\n                result = True\n\n        self.ftpcon.quit()\n\n        return result\n\n    def _rm_recursive(self, ftp, path):\n        \"\"\"\n        Recursively delete a directory tree on a remote server.\n\n        Source: https://gist.github.com/artlogic/2632647\n        \"\"\"\n        wd = ftp.pwd()\n\n        try:\n            names = ftp.nlst(path)\n        except ftplib.all_errors as e:\n            # some FTP servers complain when you try and list non-existent paths\n            return\n\n        for name in names:\n            if os.path.split(name)[1] in ('.', '..'):\n                continue\n\n            try:\n                ftp.cwd(name)  # if we can cwd to it, it's a folder\n                ftp.cwd(wd)  # don't try a nuke a folder we're in\n                self._rm_recursive(ftp, name)\n            except ftplib.all_errors:\n                ftp.delete(name)\n\n        try:\n            ftp.rmd(path)\n        except ftplib.all_errors as e:\n            print('_rm_recursive: Could not remove {0}: {1}'.format(path, e))\n\n    def remove(self, path, recursive=True):\n        \"\"\"\n        Remove file or directory at location ``path``.\n\n        :param path: a path within the FileSystem to remove.\n        :type path: str\n        :param recursive: if the path is a directory, recursively remove the directory and\n                          all of its descendants. Defaults to ``True``.\n        :type recursive: bool\n        \"\"\"\n        self._connect()\n\n        if recursive:\n            self._rm_recursive(self.ftpcon, path)\n        else:\n            try:\n                # try delete file\n                self.ftpcon.delete(path)\n            except ftplib.all_errors:\n                # it is a folder, delete it\n                self.ftpcon.rmd(path)\n\n        self.ftpcon.quit()\n\n    def put(self, local_path, path):\n        # create parent folder if not exists\n        self._connect()\n\n        normpath = os.path.normpath(path)\n        folder = os.path.dirname(normpath)\n\n        # create paths if do not exists\n        for subfolder in folder.split(os.sep):\n            if subfolder and subfolder not in self.ftpcon.nlst():\n                self.ftpcon.mkd(subfolder)\n\n            self.ftpcon.cwd(subfolder)\n\n        # go back to ftp root folder\n        self.ftpcon.cwd(\"/\")\n\n        # random file name\n        tmp_path = folder + os.sep + 'luigi-tmp-%09d' % random.randrange(0, 1e10)\n\n        self.ftpcon.storbinary('STOR %s' % tmp_path, open(local_path, 'rb'))\n        self.ftpcon.rename(tmp_path, normpath)\n\n        self.ftpcon.quit()\n\n    def get(self, path, local_path):\n        # Create folder if it does not exist\n        normpath = os.path.normpath(local_path)\n        folder = os.path.dirname(normpath)\n        if folder and not os.path.exists(folder):\n            os.makedirs(folder)\n\n        tmp_local_path = local_path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)\n        # download file\n        self._connect()\n        self.ftpcon.retrbinary('RETR %s' % path, open(tmp_local_path, 'wb').write)\n        self.ftpcon.quit()\n\n        os.rename(tmp_local_path, local_path)\n\n\nclass AtomicFtpfile(file):\n    \"\"\"\n    Simple class that writes to a temp file and upload to ftp on close().\n\n    Also cleans up the temp file if close is not invoked.\n    \"\"\"\n\n    def __init__(self, fs, path):\n        self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)\n        self._fs = fs\n        self.path = path\n        super(AtomicFtpfile, self).__init__(self.__tmp_path, 'w')\n\n    def close(self):\n        # close and upload file to ftp\n        super(AtomicFtpfile, self).close()\n        self._fs.put(self.__tmp_path, self.path)\n        os.remove(self.__tmp_path)\n\n    def __del__(self):\n        if os.path.exists(self.__tmp_path):\n            os.remove(self.__tmp_path)\n\n    @property\n    def tmp_path(self):\n        return self.__tmp_path\n\n    @property\n    def fs(self):\n        return self._fs\n\n    def __exit__(self, exc_type, exc, traceback):\n        \"\"\"\n        Close/commit the file if there are no exception\n\n        Upload file to ftp\n        \"\"\"\n        if exc_type:\n            return\n        return file.__exit__(self, exc_type, exc, traceback)\n\n\nclass RemoteTarget(luigi.target.FileSystemTarget):\n    \"\"\"\n    Target used for reading from remote files.\n\n    The target is implemented using ssh commands streaming data over the network.\n    \"\"\"\n\n    def __init__(self, path, host, format=None, username=None, password=None, port=21, mtime=None, tls=False):\n        self.path = path\n        self.mtime = mtime\n        self.format = format\n        self.tls = tls\n        self._fs = RemoteFileSystem(host, username, password, port, tls)\n\n    @property\n    def fs(self):\n        return self._fs\n\n    def open(self, mode):\n        \"\"\"\n        Open the FileSystem target.\n\n        This method returns a file-like object which can either be read from or written to depending\n        on the specified mode.\n\n        :param mode: the mode `r` opens the FileSystemTarget in read-only mode, whereas `w` will\n                     open the FileSystemTarget in write mode. Subclasses can implement\n                     additional options.\n        :type mode: str\n        \"\"\"\n        if mode == 'w':\n            if self.format:\n                return self.format.pipe_writer(AtomicFtpfile(self._fs, self.path))\n            else:\n                return AtomicFtpfile(self._fs, self.path)\n\n        elif mode == 'r':\n            self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)\n            # download file to local\n            self._fs.get(self.path, self.__tmp_path)\n\n            # manage tmp file\n            fileobj = FileWrapper(open(self.__tmp_path, 'r'))\n            if self.format:\n                return self.format.pipe_reader(fileobj)\n            return fileobj\n        else:\n            raise Exception('mode must be r/w')\n\n    def exists(self):\n        return self.fs.exists(self.path, self.mtime)\n\n    def put(self, local_path):\n        self.fs.put(local_path, self.path)\n\n    def get(self, local_path):\n        self.fs.get(self.path, local_path)\n", "path": "luigi/contrib/ftp.py"}], "after_files": [{"content": "\"\"\"\nThis library is a wrapper of ftplib.\nIt is convenient to move data from/to FTP.\n\nThere is an example on how to use it (example/ftp_experiment_outputs.py)\n\nYou can also find unittest for each class.\n\nBe aware that normal ftp do not provide secure communication.\n\"\"\"\nimport datetime\nimport os\nimport random\nimport ftplib\nimport luigi\nimport luigi.target\nimport luigi.format\nfrom luigi.format import FileWrapper\n\n\nclass RemoteFileSystem(luigi.target.FileSystem):\n\n    def __init__(self, host, username=None, password=None, port=21, tls=False):\n        self.host = host\n        self.username = username\n        self.password = password\n        self.port = port\n        self.tls = tls\n\n    def _connect(self):\n        \"\"\"\n        Log in to ftp.\n        \"\"\"\n        if self.tls:\n            self.ftpcon = ftplib.FTP_TLS()\n        else:\n            self.ftpcon = ftplib.FTP()\n        self.ftpcon.connect(self.host, self.port)\n        self.ftpcon.login(self.username, self.password)\n        if self.tls:\n            self.ftpcon.prot_p()\n\n    def exists(self, path, mtime=None):\n        \"\"\"\n        Return `True` if file or directory at `path` exist, False otherwise.\n\n        Additional check on modified time when mtime is passed in.\n\n        Return False if the file's modified time is older mtime.\n        \"\"\"\n        self._connect()\n        files = self.ftpcon.nlst(path)\n\n        result = False\n        if files:\n            if mtime:\n                mdtm = self.ftpcon.sendcmd('MDTM ' + path)\n                modified = datetime.datetime.strptime(mdtm[4:], \"%Y%m%d%H%M%S\")\n                result = modified > mtime\n            else:\n                result = True\n\n        self.ftpcon.quit()\n\n        return result\n\n    def _rm_recursive(self, ftp, path):\n        \"\"\"\n        Recursively delete a directory tree on a remote server.\n\n        Source: https://gist.github.com/artlogic/2632647\n        \"\"\"\n        wd = ftp.pwd()\n\n        try:\n            names = ftp.nlst(path)\n        except ftplib.all_errors as e:\n            # some FTP servers complain when you try and list non-existent paths\n            return\n\n        for name in names:\n            if os.path.split(name)[1] in ('.', '..'):\n                continue\n\n            try:\n                ftp.cwd(name)  # if we can cwd to it, it's a folder\n                ftp.cwd(wd)  # don't try a nuke a folder we're in\n                self._rm_recursive(ftp, name)\n            except ftplib.all_errors:\n                ftp.delete(name)\n\n        try:\n            ftp.rmd(path)\n        except ftplib.all_errors as e:\n            print('_rm_recursive: Could not remove {0}: {1}'.format(path, e))\n\n    def remove(self, path, recursive=True):\n        \"\"\"\n        Remove file or directory at location ``path``.\n\n        :param path: a path within the FileSystem to remove.\n        :type path: str\n        :param recursive: if the path is a directory, recursively remove the directory and\n                          all of its descendants. Defaults to ``True``.\n        :type recursive: bool\n        \"\"\"\n        self._connect()\n\n        if recursive:\n            self._rm_recursive(self.ftpcon, path)\n        else:\n            try:\n                # try delete file\n                self.ftpcon.delete(path)\n            except ftplib.all_errors:\n                # it is a folder, delete it\n                self.ftpcon.rmd(path)\n\n        self.ftpcon.quit()\n\n    def put(self, local_path, path):\n        # create parent folder if not exists\n        self._connect()\n\n        normpath = os.path.normpath(path)\n        folder = os.path.dirname(normpath)\n\n        # create paths if do not exists\n        for subfolder in folder.split(os.sep):\n            if subfolder and subfolder not in self.ftpcon.nlst():\n                self.ftpcon.mkd(subfolder)\n\n            self.ftpcon.cwd(subfolder)\n\n        # go back to ftp root folder\n        self.ftpcon.cwd(\"/\")\n\n        # random file name\n        tmp_path = folder + os.sep + 'luigi-tmp-%09d' % random.randrange(0, 1e10)\n\n        self.ftpcon.storbinary('STOR %s' % tmp_path, open(local_path, 'rb'))\n        self.ftpcon.rename(tmp_path, normpath)\n\n        self.ftpcon.quit()\n\n    def get(self, path, local_path):\n        # Create folder if it does not exist\n        normpath = os.path.normpath(local_path)\n        folder = os.path.dirname(normpath)\n        if folder and not os.path.exists(folder):\n            os.makedirs(folder)\n\n        tmp_local_path = local_path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)\n        # download file\n        self._connect()\n        self.ftpcon.retrbinary('RETR %s' % path, open(tmp_local_path, 'wb').write)\n        self.ftpcon.quit()\n\n        os.rename(tmp_local_path, local_path)\n\n\nclass AtomicFtpfile(file):\n    \"\"\"\n    Simple class that writes to a temp file and upload to ftp on close().\n\n    Also cleans up the temp file if close is not invoked.\n    \"\"\"\n\n    def __init__(self, fs, path):\n        \"\"\"\n        Initializes an AtomicFtpfile instance.\n\n        :param fs:\n        :param path:\n        :type path: str\n        \"\"\"\n        self.__tmp_path = '%s-luigi-tmp-%09d' % (path, random.randrange(0, 1e10))\n        self._fs = fs\n        self.path = path\n        super(AtomicFtpfile, self).__init__(self.__tmp_path, 'w')\n\n    def close(self):\n        # close and upload file to ftp\n        super(AtomicFtpfile, self).close()\n        self._fs.put(self.__tmp_path, self.path)\n        os.remove(self.__tmp_path)\n\n    def __del__(self):\n        if os.path.exists(self.__tmp_path):\n            os.remove(self.__tmp_path)\n\n    @property\n    def tmp_path(self):\n        return self.__tmp_path\n\n    @property\n    def fs(self):\n        return self._fs\n\n    def __exit__(self, exc_type, exc, traceback):\n        \"\"\"\n        Close/commit the file if there are no exception\n\n        Upload file to ftp\n        \"\"\"\n        if exc_type:\n            return\n        return file.__exit__(self, exc_type, exc, traceback)\n\n\nclass RemoteTarget(luigi.target.FileSystemTarget):\n    \"\"\"\n    Target used for reading from remote files.\n\n    The target is implemented using ssh commands streaming data over the network.\n    \"\"\"\n\n    def __init__(self, path, host, format=None, username=None, password=None, port=21, mtime=None, tls=False):\n        self.path = path\n        self.mtime = mtime\n        self.format = format\n        self.tls = tls\n        self._fs = RemoteFileSystem(host, username, password, port, tls)\n\n    @property\n    def fs(self):\n        return self._fs\n\n    def open(self, mode):\n        \"\"\"\n        Open the FileSystem target.\n\n        This method returns a file-like object which can either be read from or written to depending\n        on the specified mode.\n\n        :param mode: the mode `r` opens the FileSystemTarget in read-only mode, whereas `w` will\n                     open the FileSystemTarget in write mode. Subclasses can implement\n                     additional options.\n        :type mode: str\n        \"\"\"\n        if mode == 'w':\n            if self.format:\n                return self.format.pipe_writer(AtomicFtpfile(self._fs, self.path))\n            else:\n                return AtomicFtpfile(self._fs, self.path)\n\n        elif mode == 'r':\n            self.__tmp_path = self.path + '-luigi-tmp-%09d' % random.randrange(0, 1e10)\n            # download file to local\n            self._fs.get(self.path, self.__tmp_path)\n\n            # manage tmp file\n            fileobj = FileWrapper(open(self.__tmp_path, 'r'))\n            if self.format:\n                return self.format.pipe_reader(fileobj)\n            return fileobj\n        else:\n            raise Exception('mode must be r/w')\n\n    def exists(self):\n        return self.fs.exists(self.path, self.mtime)\n\n    def put(self, local_path):\n        self.fs.put(local_path, self.path)\n\n    def get(self, local_path):\n        self.fs.get(self.path, local_path)\n", "path": "luigi/contrib/ftp.py"}]}