We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Cannot preview artifacts in UI when uploaded to remote machine via FTP
### System information
- **Have I written custom code (as opposed to using a stock example script provided in MLflow)**:
No
- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**:
Linux Ubuntu 18.04
- **MLflow installed from (source or binary)**: 
installed via from pypi via pip
- **MLflow version (run ``mlflow --version``)**:
0.9.1
- **Python version**: 
3.6.7
- **npm version (if running the dev UI):
- **Exact command to reproduce**:
Server runs with:
```
mlflow server --backend-store-uri ./mlruns --default-artifact-root ./artifacts -h 0.0.0.0 -p 5020
```
within a folder holding a `mlruns` and a `artifacts` folder

### Describe the problem
I am running the server on a remote machine.
On the local machine which uploads via the tracking API the
tracking uri is set to: `http://path.to.server:port`
and artifact uri to: `ftp://anonymous:@path.to.server/artifacts`

uploading the tracking information and artifacts work fine and everything shows in the ui:
![image](https://user-images.githubusercontent.com/12450485/58400502-7d0e9e00-805b-11e9-8d4f-b89a1bab5cb1.png)

However when I try to click one of the artifacts I always get the message that something went wrong:
![image](https://user-images.githubusercontent.com/12450485/58400530-99aad600-805b-11e9-8887-4f2640765ba4.png)

Previewing the artifacts work when I store them locally on my machine but as soon as I transfer them via FTP and then try to preview them from the remote machine I get the error shown above.


### Source code / logs
-


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mlflow/store/artifact/ftp_artifact_repo.py`
Content:
```
1 import os
2 import ftplib
3 from ftplib import FTP
4 from contextlib import contextmanager
5 
6 import posixpath
7 from six.moves import urllib
8 
9 from mlflow.entities.file_info import FileInfo
10 from mlflow.store.artifact.artifact_repo import ArtifactRepository
11 from mlflow.utils.file_utils import relative_path_to_artifact_path
12 from mlflow.exceptions import MlflowException
13 
14 
15 class FTPArtifactRepository(ArtifactRepository):
16     """Stores artifacts as files in a remote directory, via ftp."""
17 
18     def __init__(self, artifact_uri):
19         self.uri = artifact_uri
20         parsed = urllib.parse.urlparse(artifact_uri)
21         self.config = {
22             'host': parsed.hostname,
23             'port': 21 if parsed.port is None else parsed.port,
24             'username': parsed.username,
25             'password': parsed.password
26         }
27         self.path = parsed.path
28 
29         if self.config['host'] is None:
30             self.config['host'] = 'localhost'
31 
32         super(FTPArtifactRepository, self).__init__(artifact_uri)
33 
34     @contextmanager
35     def get_ftp_client(self):
36         ftp = FTP()
37         ftp.connect(self.config['host'], self.config['port'])
38         ftp.login(self.config['username'], self.config['password'])
39         yield ftp
40         ftp.close()
41 
42     @staticmethod
43     def _is_dir(ftp, full_file_path):
44         try:
45             ftp.cwd(full_file_path)
46             return True
47         except ftplib.error_perm:
48             return False
49 
50     @staticmethod
51     def _mkdir(ftp, artifact_dir):
52         try:
53             if not FTPArtifactRepository._is_dir(ftp, artifact_dir):
54                 ftp.mkd(artifact_dir)
55         except ftplib.error_perm:
56             head, _ = posixpath.split(artifact_dir)
57             FTPArtifactRepository._mkdir(ftp, head)
58             FTPArtifactRepository._mkdir(ftp, artifact_dir)
59 
60     @staticmethod
61     def _size(ftp, full_file_path):
62         ftp.voidcmd('TYPE I')
63         size = ftp.size(full_file_path)
64         ftp.voidcmd('TYPE A')
65         return size
66 
67     def log_artifact(self, local_file, artifact_path=None):
68         with self.get_ftp_client() as ftp:
69             artifact_dir = posixpath.join(self.path, artifact_path) \
70                 if artifact_path else self.path
71             self._mkdir(ftp, artifact_dir)
72             with open(local_file, 'rb') as f:
73                 ftp.cwd(artifact_dir)
74                 ftp.storbinary('STOR ' + os.path.basename(local_file), f)
75 
76     def log_artifacts(self, local_dir, artifact_path=None):
77         dest_path = posixpath.join(self.path, artifact_path) \
78             if artifact_path else self.path
79 
80         dest_path = posixpath.join(
81             dest_path, os.path.split(local_dir)[1])
82         dest_path_re = os.path.split(local_dir)[1]
83         if artifact_path:
84             dest_path_re = posixpath.join(
85                 artifact_path, os.path.split(local_dir)[1])
86 
87         local_dir = os.path.abspath(local_dir)
88         for (root, _, filenames) in os.walk(local_dir):
89             upload_path = dest_path
90             if root != local_dir:
91                 rel_path = os.path.relpath(root, local_dir)
92                 rel_path = relative_path_to_artifact_path(rel_path)
93                 upload_path = posixpath.join(dest_path_re, rel_path)
94             if not filenames:
95                 with self.get_ftp_client() as ftp:
96                     self._mkdir(ftp, posixpath.join(self.path, upload_path))
97             for f in filenames:
98                 if os.path.isfile(os.path.join(root, f)):
99                     self.log_artifact(os.path.join(root, f), upload_path)
100 
101     def _is_directory(self, artifact_path):
102         artifact_dir = self.path
103         list_dir = posixpath.join(artifact_dir, artifact_path) if artifact_path else artifact_dir
104         with self.get_ftp_client() as ftp:
105             return self._is_dir(ftp, list_dir)
106 
107     def list_artifacts(self, path=None):
108         with self.get_ftp_client() as ftp:
109             artifact_dir = self.path
110             list_dir = posixpath.join(artifact_dir, path) if path else artifact_dir
111             if not self._is_dir(ftp, list_dir):
112                 return []
113             artifact_files = ftp.nlst(list_dir)
114             infos = []
115             for file_name in artifact_files:
116                 file_path = (file_name if path is None
117                              else posixpath.join(path, file_name))
118                 full_file_path = posixpath.join(list_dir, file_name)
119                 if self._is_dir(ftp, full_file_path):
120                     infos.append(FileInfo(file_path, True, None))
121                 else:
122                     size = self._size(ftp, full_file_path)
123                     infos.append(FileInfo(file_path, False, size))
124         return infos
125 
126     def _download_file(self, remote_file_path, local_path):
127         remote_full_path = posixpath.join(self.path, remote_file_path) \
128             if remote_file_path else self.path
129         with self.get_ftp_client() as ftp:
130             with open(local_path, 'wb') as f:
131                 ftp.retrbinary('RETR ' + remote_full_path, f.write)
132 
133     def delete_artifacts(self, artifact_path=None):
134         raise MlflowException('Not implemented yet')
135
```
--- 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/mlflow/store/artifact/ftp_artifact_repo.py b/mlflow/store/artifact/ftp_artifact_repo.py
--- a/mlflow/store/artifact/ftp_artifact_repo.py
+++ b/mlflow/store/artifact/ftp_artifact_repo.py
@@ -111,6 +111,7 @@
             if not self._is_dir(ftp, list_dir):
                 return []
             artifact_files = ftp.nlst(list_dir)
+            artifact_files = list(filter(lambda x: x != "." and x != "..", artifact_files))
             infos = []
             for file_name in artifact_files:
                 file_path = (file_name if path is None

{"golden_diff": "diff --git a/mlflow/store/artifact/ftp_artifact_repo.py b/mlflow/store/artifact/ftp_artifact_repo.py\n--- a/mlflow/store/artifact/ftp_artifact_repo.py\n+++ b/mlflow/store/artifact/ftp_artifact_repo.py\n@@ -111,6 +111,7 @@\n             if not self._is_dir(ftp, list_dir):\n                 return []\n             artifact_files = ftp.nlst(list_dir)\n+            artifact_files = list(filter(lambda x: x != \".\" and x != \"..\", artifact_files))\n             infos = []\n             for file_name in artifact_files:\n                 file_path = (file_name if path is None\n", "issue": "Cannot preview artifacts in UI when uploaded to remote machine via FTP\n### System information\r\n- **Have I written custom code (as opposed to using a stock example script provided in MLflow)**:\r\nNo\r\n- **OS Platform and Distribution (e.g., Linux Ubuntu 16.04)**:\r\nLinux Ubuntu 18.04\r\n- **MLflow installed from (source or binary)**: \r\ninstalled via from pypi via pip\r\n- **MLflow version (run ``mlflow --version``)**:\r\n0.9.1\r\n- **Python version**: \r\n3.6.7\r\n- **npm version (if running the dev UI):\r\n- **Exact command to reproduce**:\r\nServer runs with:\r\n```\r\nmlflow server --backend-store-uri ./mlruns --default-artifact-root ./artifacts -h 0.0.0.0 -p 5020\r\n```\r\nwithin a folder holding a `mlruns` and a `artifacts` folder\r\n\r\n### Describe the problem\r\nI am running the server on a remote machine.\r\nOn the local machine which uploads via the tracking API the\r\ntracking uri is set to: `http://path.to.server:port`\r\nand artifact uri to: `ftp://anonymous:@path.to.server/artifacts`\r\n\r\nuploading the tracking information and artifacts work fine and everything shows in the ui:\r\n![image](https://user-images.githubusercontent.com/12450485/58400502-7d0e9e00-805b-11e9-8d4f-b89a1bab5cb1.png)\r\n\r\nHowever when I try to click one of the artifacts I always get the message that something went wrong:\r\n![image](https://user-images.githubusercontent.com/12450485/58400530-99aad600-805b-11e9-8887-4f2640765ba4.png)\r\n\r\nPreviewing the artifacts work when I store them locally on my machine but as soon as I transfer them via FTP and then try to preview them from the remote machine I get the error shown above.\r\n\r\n\r\n### Source code / logs\r\n-\r\n\n", "before_files": [{"content": "import os\nimport ftplib\nfrom ftplib import FTP\nfrom contextlib import contextmanager\n\nimport posixpath\nfrom six.moves import urllib\n\nfrom mlflow.entities.file_info import FileInfo\nfrom mlflow.store.artifact.artifact_repo import ArtifactRepository\nfrom mlflow.utils.file_utils import relative_path_to_artifact_path\nfrom mlflow.exceptions import MlflowException\n\n\nclass FTPArtifactRepository(ArtifactRepository):\n    \"\"\"Stores artifacts as files in a remote directory, via ftp.\"\"\"\n\n    def __init__(self, artifact_uri):\n        self.uri = artifact_uri\n        parsed = urllib.parse.urlparse(artifact_uri)\n        self.config = {\n            'host': parsed.hostname,\n            'port': 21 if parsed.port is None else parsed.port,\n            'username': parsed.username,\n            'password': parsed.password\n        }\n        self.path = parsed.path\n\n        if self.config['host'] is None:\n            self.config['host'] = 'localhost'\n\n        super(FTPArtifactRepository, self).__init__(artifact_uri)\n\n    @contextmanager\n    def get_ftp_client(self):\n        ftp = FTP()\n        ftp.connect(self.config['host'], self.config['port'])\n        ftp.login(self.config['username'], self.config['password'])\n        yield ftp\n        ftp.close()\n\n    @staticmethod\n    def _is_dir(ftp, full_file_path):\n        try:\n            ftp.cwd(full_file_path)\n            return True\n        except ftplib.error_perm:\n            return False\n\n    @staticmethod\n    def _mkdir(ftp, artifact_dir):\n        try:\n            if not FTPArtifactRepository._is_dir(ftp, artifact_dir):\n                ftp.mkd(artifact_dir)\n        except ftplib.error_perm:\n            head, _ = posixpath.split(artifact_dir)\n            FTPArtifactRepository._mkdir(ftp, head)\n            FTPArtifactRepository._mkdir(ftp, artifact_dir)\n\n    @staticmethod\n    def _size(ftp, full_file_path):\n        ftp.voidcmd('TYPE I')\n        size = ftp.size(full_file_path)\n        ftp.voidcmd('TYPE A')\n        return size\n\n    def log_artifact(self, local_file, artifact_path=None):\n        with self.get_ftp_client() as ftp:\n            artifact_dir = posixpath.join(self.path, artifact_path) \\\n                if artifact_path else self.path\n            self._mkdir(ftp, artifact_dir)\n            with open(local_file, 'rb') as f:\n                ftp.cwd(artifact_dir)\n                ftp.storbinary('STOR ' + os.path.basename(local_file), f)\n\n    def log_artifacts(self, local_dir, artifact_path=None):\n        dest_path = posixpath.join(self.path, artifact_path) \\\n            if artifact_path else self.path\n\n        dest_path = posixpath.join(\n            dest_path, os.path.split(local_dir)[1])\n        dest_path_re = os.path.split(local_dir)[1]\n        if artifact_path:\n            dest_path_re = posixpath.join(\n                artifact_path, os.path.split(local_dir)[1])\n\n        local_dir = os.path.abspath(local_dir)\n        for (root, _, filenames) in os.walk(local_dir):\n            upload_path = dest_path\n            if root != local_dir:\n                rel_path = os.path.relpath(root, local_dir)\n                rel_path = relative_path_to_artifact_path(rel_path)\n                upload_path = posixpath.join(dest_path_re, rel_path)\n            if not filenames:\n                with self.get_ftp_client() as ftp:\n                    self._mkdir(ftp, posixpath.join(self.path, upload_path))\n            for f in filenames:\n                if os.path.isfile(os.path.join(root, f)):\n                    self.log_artifact(os.path.join(root, f), upload_path)\n\n    def _is_directory(self, artifact_path):\n        artifact_dir = self.path\n        list_dir = posixpath.join(artifact_dir, artifact_path) if artifact_path else artifact_dir\n        with self.get_ftp_client() as ftp:\n            return self._is_dir(ftp, list_dir)\n\n    def list_artifacts(self, path=None):\n        with self.get_ftp_client() as ftp:\n            artifact_dir = self.path\n            list_dir = posixpath.join(artifact_dir, path) if path else artifact_dir\n            if not self._is_dir(ftp, list_dir):\n                return []\n            artifact_files = ftp.nlst(list_dir)\n            infos = []\n            for file_name in artifact_files:\n                file_path = (file_name if path is None\n                             else posixpath.join(path, file_name))\n                full_file_path = posixpath.join(list_dir, file_name)\n                if self._is_dir(ftp, full_file_path):\n                    infos.append(FileInfo(file_path, True, None))\n                else:\n                    size = self._size(ftp, full_file_path)\n                    infos.append(FileInfo(file_path, False, size))\n        return infos\n\n    def _download_file(self, remote_file_path, local_path):\n        remote_full_path = posixpath.join(self.path, remote_file_path) \\\n            if remote_file_path else self.path\n        with self.get_ftp_client() as ftp:\n            with open(local_path, 'wb') as f:\n                ftp.retrbinary('RETR ' + remote_full_path, f.write)\n\n    def delete_artifacts(self, artifact_path=None):\n        raise MlflowException('Not implemented yet')\n", "path": "mlflow/store/artifact/ftp_artifact_repo.py"}], "after_files": [{"content": "import os\nimport ftplib\nfrom ftplib import FTP\nfrom contextlib import contextmanager\n\nimport posixpath\nfrom six.moves import urllib\n\nfrom mlflow.entities.file_info import FileInfo\nfrom mlflow.store.artifact.artifact_repo import ArtifactRepository\nfrom mlflow.utils.file_utils import relative_path_to_artifact_path\nfrom mlflow.exceptions import MlflowException\n\n\nclass FTPArtifactRepository(ArtifactRepository):\n    \"\"\"Stores artifacts as files in a remote directory, via ftp.\"\"\"\n\n    def __init__(self, artifact_uri):\n        self.uri = artifact_uri\n        parsed = urllib.parse.urlparse(artifact_uri)\n        self.config = {\n            'host': parsed.hostname,\n            'port': 21 if parsed.port is None else parsed.port,\n            'username': parsed.username,\n            'password': parsed.password\n        }\n        self.path = parsed.path\n\n        if self.config['host'] is None:\n            self.config['host'] = 'localhost'\n\n        super(FTPArtifactRepository, self).__init__(artifact_uri)\n\n    @contextmanager\n    def get_ftp_client(self):\n        ftp = FTP()\n        ftp.connect(self.config['host'], self.config['port'])\n        ftp.login(self.config['username'], self.config['password'])\n        yield ftp\n        ftp.close()\n\n    @staticmethod\n    def _is_dir(ftp, full_file_path):\n        try:\n            ftp.cwd(full_file_path)\n            return True\n        except ftplib.error_perm:\n            return False\n\n    @staticmethod\n    def _mkdir(ftp, artifact_dir):\n        try:\n            if not FTPArtifactRepository._is_dir(ftp, artifact_dir):\n                ftp.mkd(artifact_dir)\n        except ftplib.error_perm:\n            head, _ = posixpath.split(artifact_dir)\n            FTPArtifactRepository._mkdir(ftp, head)\n            FTPArtifactRepository._mkdir(ftp, artifact_dir)\n\n    @staticmethod\n    def _size(ftp, full_file_path):\n        ftp.voidcmd('TYPE I')\n        size = ftp.size(full_file_path)\n        ftp.voidcmd('TYPE A')\n        return size\n\n    def log_artifact(self, local_file, artifact_path=None):\n        with self.get_ftp_client() as ftp:\n            artifact_dir = posixpath.join(self.path, artifact_path) \\\n                if artifact_path else self.path\n            self._mkdir(ftp, artifact_dir)\n            with open(local_file, 'rb') as f:\n                ftp.cwd(artifact_dir)\n                ftp.storbinary('STOR ' + os.path.basename(local_file), f)\n\n    def log_artifacts(self, local_dir, artifact_path=None):\n        dest_path = posixpath.join(self.path, artifact_path) \\\n            if artifact_path else self.path\n\n        dest_path = posixpath.join(\n            dest_path, os.path.split(local_dir)[1])\n        dest_path_re = os.path.split(local_dir)[1]\n        if artifact_path:\n            dest_path_re = posixpath.join(\n                artifact_path, os.path.split(local_dir)[1])\n\n        local_dir = os.path.abspath(local_dir)\n        for (root, _, filenames) in os.walk(local_dir):\n            upload_path = dest_path\n            if root != local_dir:\n                rel_path = os.path.relpath(root, local_dir)\n                rel_path = relative_path_to_artifact_path(rel_path)\n                upload_path = posixpath.join(dest_path_re, rel_path)\n            if not filenames:\n                with self.get_ftp_client() as ftp:\n                    self._mkdir(ftp, posixpath.join(self.path, upload_path))\n            for f in filenames:\n                if os.path.isfile(os.path.join(root, f)):\n                    self.log_artifact(os.path.join(root, f), upload_path)\n\n    def _is_directory(self, artifact_path):\n        artifact_dir = self.path\n        list_dir = posixpath.join(artifact_dir, artifact_path) if artifact_path else artifact_dir\n        with self.get_ftp_client() as ftp:\n            return self._is_dir(ftp, list_dir)\n\n    def list_artifacts(self, path=None):\n        with self.get_ftp_client() as ftp:\n            artifact_dir = self.path\n            list_dir = posixpath.join(artifact_dir, path) if path else artifact_dir\n            if not self._is_dir(ftp, list_dir):\n                return []\n            artifact_files = ftp.nlst(list_dir)\n            artifact_files = list(filter(lambda x: x != \".\" and x != \"..\", artifact_files))\n            infos = []\n            for file_name in artifact_files:\n                file_path = (file_name if path is None\n                             else posixpath.join(path, file_name))\n                full_file_path = posixpath.join(list_dir, file_name)\n                if self._is_dir(ftp, full_file_path):\n                    infos.append(FileInfo(file_path, True, None))\n                else:\n                    size = self._size(ftp, full_file_path)\n                    infos.append(FileInfo(file_path, False, size))\n        return infos\n\n    def _download_file(self, remote_file_path, local_path):\n        remote_full_path = posixpath.join(self.path, remote_file_path) \\\n            if remote_file_path else self.path\n        with self.get_ftp_client() as ftp:\n            with open(local_path, 'wb') as f:\n                ftp.retrbinary('RETR ' + remote_full_path, f.write)\n\n    def delete_artifacts(self, artifact_path=None):\n        raise MlflowException('Not implemented yet')\n", "path": "mlflow/store/artifact/ftp_artifact_repo.py"}]}