We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Can't load dataset on latest develop
On latest `develop`, after rerunning the install script, I see:
```py
import fiftyone as fo                                                                                                                                                        
import fiftyone.zoo as foz                                                                                                                                                   

dataset = foz.load_zoo_dataset("cifar10", split="test")                                                                                                                      
Split 'test' already downloaded
Loading existing dataset 'cifar10-test'. To reload from disk, first delete the existing dataset

fo.launch_dashboard(dataset) 
```

<img width="1662" alt="Screen Shot 2020-06-10 at 5 50 09 PM" src="https://user-images.githubusercontent.com/25985824/84322368-dd775d00-ab42-11ea-8d96-31dcdb3ea85b.png">


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `fiftyone/server/main.py`
Content:
```
1 """
2 FiftyOne Flask server.
3 
4 | Copyright 2017-2020, Voxel51, Inc.
5 | `voxel51.com <https://voxel51.com/>`_
6 |
7 """
8 # pragma pylint: disable=redefined-builtin
9 # pragma pylint: disable=unused-wildcard-import
10 # pragma pylint: disable=wildcard-import
11 from __future__ import absolute_import
12 from __future__ import division
13 from __future__ import print_function
14 from __future__ import unicode_literals
15 from builtins import *
16 
17 # pragma pylint: enable=redefined-builtin
18 # pragma pylint: enable=unused-wildcard-import
19 # pragma pylint: enable=wildcard-import
20 
21 import logging
22 import os
23 
24 from flask import Flask, request, send_file
25 from flask_socketio import emit, Namespace, SocketIO
26 
27 os.environ["FIFTYONE_SERVER"] = "1"
28 import fiftyone.core.fields as fof
29 import fiftyone.core.state as fos
30 
31 from util import get_image_size
32 from pipelines import DISTRIBUTION_PIPELINES, LABELS, SCALARS
33 
34 logger = logging.getLogger(__name__)
35 
36 app = Flask(__name__)
37 app.config["SECRET_KEY"] = "fiftyone"
38 
39 socketio = SocketIO(app, async_mode="eventlet", cors_allowed_origin="*")
40 
41 
42 @app.route("/")
43 def get_sample_media():
44     """Gets the sample media.
45 
46     Returns:
47         bytes
48     """
49     path = request.args.get("path")
50     return send_file(path)
51 
52 
53 def _load_state(func):
54     def wrapper(self, *args, **kwargs):
55         state = fos.StateDescription.from_dict(self.state)
56         state = func(self, state, *args, **kwargs)
57         self.state = state.serialize()
58         emit("update", self.state, broadcast=True, include_self=False)
59         return self.state
60 
61     return wrapper
62 
63 
64 class StateController(Namespace):
65     """State controller.
66 
67     Attributes:
68         state: a :class:`fiftyone.core.state.StateDescription` instance
69 
70     Args:
71         **args: postional arguments for ``flask_socketio.Namespace``
72         **kwargs: keyword arguments for ``flask_socketio.Namespace``
73     """
74 
75     def __init__(self, *args, **kwargs):
76         self.state = fos.StateDescription().serialize()
77         super(StateController, self).__init__(*args, **kwargs)
78 
79     def on_connect(self):
80         """Handles connection to the server."""
81         pass
82 
83     def on_disconnect(self):
84         """Handles disconnection from the server."""
85         pass
86 
87     def on_update(self, state):
88         """Updates the state.
89 
90         Args:
91             state: a serialized :class:`fiftyone.core.state.StateDescription`
92         """
93         self.state = state
94         emit("update", state, broadcast=True, include_self=False)
95 
96     def on_get_current_state(self, _):
97         """Gets the current state.
98 
99         Returns:
100             a :class:`fiftyone.core.state.StateDescription`
101         """
102         return self.state
103 
104     @_load_state
105     def on_add_selection(self, state, _id):
106         """Adds a sample to the selected samples list.
107 
108         Args:
109             state: the current :class:`fiftyone.core.state.StateDescription`
110             _id: the sample ID
111 
112         Returns:
113             the updated :class:`fiftyone.core.state.StateDescription`
114         """
115         selected = set(state.selected)
116         selected.add(_id)
117         state.selected = list(selected)
118         return state
119 
120     @_load_state
121     def on_remove_selection(self, state, _id):
122         """Remove a sample from the selected samples list
123 
124         Args:
125             state: the current :class:`fiftyone.core.state.StateDescription`
126             _id: the sample ID
127 
128         Returns:
129             the updated :class:`fiftyone.core.state.StateDescription`
130         """
131         selected = set(state.selected)
132         selected.remove(_id)
133         state.selected = list(selected)
134         return state
135 
136     def on_page(self, page, page_length=20):
137         """Gets the requested page of samples.
138 
139         Args:
140             page: the page number
141             page_length: the page length
142 
143         Returns:
144             the list of sample dicts for the page
145         """
146         state = fos.StateDescription.from_dict(self.state)
147         if state.view is not None:
148             view = state.view
149         elif state.dataset is not None:
150             view = state.dataset.view()
151         else:
152             return []
153 
154         view = view.skip((page - 1) * page_length).limit(page_length + 1)
155         samples = [s.to_dict(extended=True) for s in view]
156         more = False
157         if len(samples) > page_length:
158             samples = samples[:page_length]
159             more = page + 1
160 
161         results = [{"sample": s} for s in samples]
162         for r in results:
163             w, h = get_image_size(r["sample"]["filepath"])
164             r["width"] = w
165             r["height"] = h
166 
167         return {"results": results, "more": more}
168 
169     def on_lengths(self, _):
170         state = fos.StateDescription.from_dict(self.state)
171         if state.view is not None:
172             view = state.view
173         elif state.dataset is not None:
174             view = state.dataset.view()
175         else:
176             return []
177         return {"labels": view.get_label_fields(), "tags": view.get_tags()}
178 
179     def on_get_distributions(self, group):
180         """Gets the distributions for the current state with respect to a group,
181 
182         Args:
183             group: one of "labels", "tags", or "scalars"
184 
185         Returns:
186             a list of distributions
187         """
188         state = fos.StateDescription.from_dict(self.state)
189         if state.view is not None:
190             view = state.view
191         elif state.dataset is not None:
192             view = state.dataset.view()
193         else:
194             return []
195 
196         return _get_distributions(view, group)
197 
198     def on_get_facets(self, _):
199         """Gets the facets for the current state.
200 
201         Args:
202             _: the message, which is not used
203 
204         Returns:
205             the list of facets
206         """
207         state = fos.StateDescription.from_dict(self.state)
208         if state.view is not None:
209             view = state.view
210         elif state.dataset is not None:
211             view = state.dataset.view()
212         else:
213             return []
214 
215         return view._get_facets()
216 
217     def on_set_facets(self, facets):
218         """Sets the facets for the current state.
219 
220         Args:
221             facets: the facets string
222         """
223         _, value = facets.split(".")
224         state = fos.StateDescription.from_dict(self.state)
225         state.view = state.dataset.view().match_tag(value)
226         self.state = state.serialize()
227         emit("update", self.state, broadcast=True, include_self=True)
228 
229 
230 def _get_distributions(view, group):
231     pipeline = DISTRIBUTION_PIPELINES[group]
232 
233     # we add a sub-pipeline for each numeric as it looks like multiple
234     # buckets in a single pipeline is not supported
235     if group == SCALARS:
236         _numeric_distribution_pipelines(view, pipeline)
237 
238     result = list(view.aggregate(pipeline))
239 
240     if group in {LABELS, SCALARS}:
241         new_result = []
242         for f in result[0].values():
243             new_result += f
244         result = new_result
245 
246     if group != SCALARS:
247         for idx, dist in enumerate(result):
248             result[idx]["data"] = sorted(
249                 result[idx]["data"], key=lambda c: c["count"], reverse=True
250             )
251 
252     return sorted(result, key=lambda d: d["name"])
253 
254 
255 def _numeric_bounds(view, numerics):
256     bounds_pipeline = [{"$facet": {}}]
257     for idx, (k, v) in enumerate(numerics.items()):
258         bounds_pipeline[0]["$facet"]["numeric-%d" % idx] = [
259             {
260                 "$group": {
261                     "_id": k,
262                     "min": {"$min": "$%s" % k},
263                     "max": {"$max": "$%s" % k},
264                 },
265             }
266         ]
267 
268     return list(view.aggregate(bounds_pipeline))[0] if len(numerics) else {}
269 
270 
271 def _numeric_distribution_pipelines(view, pipeline, buckets=50):
272     numerics = view._dataset.get_field_schema(ftype=fof.IntField)
273     numerics.update(view._dataset.get_field_schema(ftype=fof.FloatField))
274 
275     # here we query the min and max for each numeric field
276     # unfortunately, it looks like this has to be a separate query
277     bounds = _numeric_bounds(view, numerics)
278 
279     # for each numeric field, build the boundaries array with the
280     # min/max results when adding the field's sub-pipeline
281     for idx, (k, v) in enumerate(numerics.items()):
282         sub_pipeline = "numeric-%d" % idx
283         field_bounds = bounds[sub_pipeline][0]
284         mn = field_bounds["min"]
285         mx = field_bounds["max"]
286         step = (mx - mn) / buckets
287         boundaries = [mn + step * s for s in range(0, buckets)]
288 
289         pipeline[0]["$facet"][sub_pipeline] = [
290             {
291                 "$bucket": {
292                     "groupBy": "$%s" % k,
293                     "boundaries": boundaries,
294                     "default": "null",
295                     "output": {"count": {"$sum": 1}},
296                 }
297             },
298             {
299                 "$group": {
300                     "_id": k,
301                     "data": {
302                         "$push": {
303                             "key": {
304                                 "$cond": [
305                                     {"$ne": ["$_id", "null"]},
306                                     {"$add": ["$_id", step / 2]},
307                                     "null",
308                                 ]
309                             },
310                             "count": "$count",
311                         }
312                     },
313                 }
314             },
315             {
316                 "$project": {
317                     "name": k,
318                     "type": v.__class__.__name__[
319                         : -len("Field")  # grab field type from the class
320                     ].lower(),
321                     "data": "$data",
322                 }
323             },
324         ]
325 
326 
327 socketio.on_namespace(StateController("/state"))
328 
329 
330 if __name__ == "__main__":
331     socketio.run(app, debug=True)
332
```
--- 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/fiftyone/server/main.py b/fiftyone/server/main.py
--- a/fiftyone/server/main.py
+++ b/fiftyone/server/main.py
@@ -18,9 +18,11 @@
 # pragma pylint: enable=unused-wildcard-import
 # pragma pylint: enable=wildcard-import
 
+import json
 import logging
 import os
 
+from bson import json_util
 from flask import Flask, request, send_file
 from flask_socketio import emit, Namespace, SocketIO
 
@@ -152,7 +154,9 @@
             return []
 
         view = view.skip((page - 1) * page_length).limit(page_length + 1)
-        samples = [s.to_dict(extended=True) for s in view]
+        samples = [
+            json.loads(json_util.dumps(s.to_mongo_dict())) for s in view
+        ]
         more = False
         if len(samples) > page_length:
             samples = samples[:page_length]

{"golden_diff": "diff --git a/fiftyone/server/main.py b/fiftyone/server/main.py\n--- a/fiftyone/server/main.py\n+++ b/fiftyone/server/main.py\n@@ -18,9 +18,11 @@\n # pragma pylint: enable=unused-wildcard-import\n # pragma pylint: enable=wildcard-import\n \n+import json\n import logging\n import os\n \n+from bson import json_util\n from flask import Flask, request, send_file\n from flask_socketio import emit, Namespace, SocketIO\n \n@@ -152,7 +154,9 @@\n             return []\n \n         view = view.skip((page - 1) * page_length).limit(page_length + 1)\n-        samples = [s.to_dict(extended=True) for s in view]\n+        samples = [\n+            json.loads(json_util.dumps(s.to_mongo_dict())) for s in view\n+        ]\n         more = False\n         if len(samples) > page_length:\n             samples = samples[:page_length]\n", "issue": "Can't load dataset on latest develop\nOn latest `develop`, after rerunning the install script, I see:\r\n```py\r\nimport fiftyone as fo                                                                                                                                                        \r\nimport fiftyone.zoo as foz                                                                                                                                                   \r\n\r\ndataset = foz.load_zoo_dataset(\"cifar10\", split=\"test\")                                                                                                                      \r\nSplit 'test' already downloaded\r\nLoading existing dataset 'cifar10-test'. To reload from disk, first delete the existing dataset\r\n\r\nfo.launch_dashboard(dataset) \r\n```\r\n\r\n<img width=\"1662\" alt=\"Screen Shot 2020-06-10 at 5 50 09 PM\" src=\"https://user-images.githubusercontent.com/25985824/84322368-dd775d00-ab42-11ea-8d96-31dcdb3ea85b.png\">\r\n\n", "before_files": [{"content": "\"\"\"\nFiftyOne Flask server.\n\n| Copyright 2017-2020, Voxel51, Inc.\n| `voxel51.com <https://voxel51.com/>`_\n|\n\"\"\"\n# pragma pylint: disable=redefined-builtin\n# pragma pylint: disable=unused-wildcard-import\n# pragma pylint: disable=wildcard-import\nfrom __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\nfrom builtins import *\n\n# pragma pylint: enable=redefined-builtin\n# pragma pylint: enable=unused-wildcard-import\n# pragma pylint: enable=wildcard-import\n\nimport logging\nimport os\n\nfrom flask import Flask, request, send_file\nfrom flask_socketio import emit, Namespace, SocketIO\n\nos.environ[\"FIFTYONE_SERVER\"] = \"1\"\nimport fiftyone.core.fields as fof\nimport fiftyone.core.state as fos\n\nfrom util import get_image_size\nfrom pipelines import DISTRIBUTION_PIPELINES, LABELS, SCALARS\n\nlogger = logging.getLogger(__name__)\n\napp = Flask(__name__)\napp.config[\"SECRET_KEY\"] = \"fiftyone\"\n\nsocketio = SocketIO(app, async_mode=\"eventlet\", cors_allowed_origin=\"*\")\n\n\n@app.route(\"/\")\ndef get_sample_media():\n    \"\"\"Gets the sample media.\n\n    Returns:\n        bytes\n    \"\"\"\n    path = request.args.get(\"path\")\n    return send_file(path)\n\n\ndef _load_state(func):\n    def wrapper(self, *args, **kwargs):\n        state = fos.StateDescription.from_dict(self.state)\n        state = func(self, state, *args, **kwargs)\n        self.state = state.serialize()\n        emit(\"update\", self.state, broadcast=True, include_self=False)\n        return self.state\n\n    return wrapper\n\n\nclass StateController(Namespace):\n    \"\"\"State controller.\n\n    Attributes:\n        state: a :class:`fiftyone.core.state.StateDescription` instance\n\n    Args:\n        **args: postional arguments for ``flask_socketio.Namespace``\n        **kwargs: keyword arguments for ``flask_socketio.Namespace``\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        self.state = fos.StateDescription().serialize()\n        super(StateController, self).__init__(*args, **kwargs)\n\n    def on_connect(self):\n        \"\"\"Handles connection to the server.\"\"\"\n        pass\n\n    def on_disconnect(self):\n        \"\"\"Handles disconnection from the server.\"\"\"\n        pass\n\n    def on_update(self, state):\n        \"\"\"Updates the state.\n\n        Args:\n            state: a serialized :class:`fiftyone.core.state.StateDescription`\n        \"\"\"\n        self.state = state\n        emit(\"update\", state, broadcast=True, include_self=False)\n\n    def on_get_current_state(self, _):\n        \"\"\"Gets the current state.\n\n        Returns:\n            a :class:`fiftyone.core.state.StateDescription`\n        \"\"\"\n        return self.state\n\n    @_load_state\n    def on_add_selection(self, state, _id):\n        \"\"\"Adds a sample to the selected samples list.\n\n        Args:\n            state: the current :class:`fiftyone.core.state.StateDescription`\n            _id: the sample ID\n\n        Returns:\n            the updated :class:`fiftyone.core.state.StateDescription`\n        \"\"\"\n        selected = set(state.selected)\n        selected.add(_id)\n        state.selected = list(selected)\n        return state\n\n    @_load_state\n    def on_remove_selection(self, state, _id):\n        \"\"\"Remove a sample from the selected samples list\n\n        Args:\n            state: the current :class:`fiftyone.core.state.StateDescription`\n            _id: the sample ID\n\n        Returns:\n            the updated :class:`fiftyone.core.state.StateDescription`\n        \"\"\"\n        selected = set(state.selected)\n        selected.remove(_id)\n        state.selected = list(selected)\n        return state\n\n    def on_page(self, page, page_length=20):\n        \"\"\"Gets the requested page of samples.\n\n        Args:\n            page: the page number\n            page_length: the page length\n\n        Returns:\n            the list of sample dicts for the page\n        \"\"\"\n        state = fos.StateDescription.from_dict(self.state)\n        if state.view is not None:\n            view = state.view\n        elif state.dataset is not None:\n            view = state.dataset.view()\n        else:\n            return []\n\n        view = view.skip((page - 1) * page_length).limit(page_length + 1)\n        samples = [s.to_dict(extended=True) for s in view]\n        more = False\n        if len(samples) > page_length:\n            samples = samples[:page_length]\n            more = page + 1\n\n        results = [{\"sample\": s} for s in samples]\n        for r in results:\n            w, h = get_image_size(r[\"sample\"][\"filepath\"])\n            r[\"width\"] = w\n            r[\"height\"] = h\n\n        return {\"results\": results, \"more\": more}\n\n    def on_lengths(self, _):\n        state = fos.StateDescription.from_dict(self.state)\n        if state.view is not None:\n            view = state.view\n        elif state.dataset is not None:\n            view = state.dataset.view()\n        else:\n            return []\n        return {\"labels\": view.get_label_fields(), \"tags\": view.get_tags()}\n\n    def on_get_distributions(self, group):\n        \"\"\"Gets the distributions for the current state with respect to a group,\n\n        Args:\n            group: one of \"labels\", \"tags\", or \"scalars\"\n\n        Returns:\n            a list of distributions\n        \"\"\"\n        state = fos.StateDescription.from_dict(self.state)\n        if state.view is not None:\n            view = state.view\n        elif state.dataset is not None:\n            view = state.dataset.view()\n        else:\n            return []\n\n        return _get_distributions(view, group)\n\n    def on_get_facets(self, _):\n        \"\"\"Gets the facets for the current state.\n\n        Args:\n            _: the message, which is not used\n\n        Returns:\n            the list of facets\n        \"\"\"\n        state = fos.StateDescription.from_dict(self.state)\n        if state.view is not None:\n            view = state.view\n        elif state.dataset is not None:\n            view = state.dataset.view()\n        else:\n            return []\n\n        return view._get_facets()\n\n    def on_set_facets(self, facets):\n        \"\"\"Sets the facets for the current state.\n\n        Args:\n            facets: the facets string\n        \"\"\"\n        _, value = facets.split(\".\")\n        state = fos.StateDescription.from_dict(self.state)\n        state.view = state.dataset.view().match_tag(value)\n        self.state = state.serialize()\n        emit(\"update\", self.state, broadcast=True, include_self=True)\n\n\ndef _get_distributions(view, group):\n    pipeline = DISTRIBUTION_PIPELINES[group]\n\n    # we add a sub-pipeline for each numeric as it looks like multiple\n    # buckets in a single pipeline is not supported\n    if group == SCALARS:\n        _numeric_distribution_pipelines(view, pipeline)\n\n    result = list(view.aggregate(pipeline))\n\n    if group in {LABELS, SCALARS}:\n        new_result = []\n        for f in result[0].values():\n            new_result += f\n        result = new_result\n\n    if group != SCALARS:\n        for idx, dist in enumerate(result):\n            result[idx][\"data\"] = sorted(\n                result[idx][\"data\"], key=lambda c: c[\"count\"], reverse=True\n            )\n\n    return sorted(result, key=lambda d: d[\"name\"])\n\n\ndef _numeric_bounds(view, numerics):\n    bounds_pipeline = [{\"$facet\": {}}]\n    for idx, (k, v) in enumerate(numerics.items()):\n        bounds_pipeline[0][\"$facet\"][\"numeric-%d\" % idx] = [\n            {\n                \"$group\": {\n                    \"_id\": k,\n                    \"min\": {\"$min\": \"$%s\" % k},\n                    \"max\": {\"$max\": \"$%s\" % k},\n                },\n            }\n        ]\n\n    return list(view.aggregate(bounds_pipeline))[0] if len(numerics) else {}\n\n\ndef _numeric_distribution_pipelines(view, pipeline, buckets=50):\n    numerics = view._dataset.get_field_schema(ftype=fof.IntField)\n    numerics.update(view._dataset.get_field_schema(ftype=fof.FloatField))\n\n    # here we query the min and max for each numeric field\n    # unfortunately, it looks like this has to be a separate query\n    bounds = _numeric_bounds(view, numerics)\n\n    # for each numeric field, build the boundaries array with the\n    # min/max results when adding the field's sub-pipeline\n    for idx, (k, v) in enumerate(numerics.items()):\n        sub_pipeline = \"numeric-%d\" % idx\n        field_bounds = bounds[sub_pipeline][0]\n        mn = field_bounds[\"min\"]\n        mx = field_bounds[\"max\"]\n        step = (mx - mn) / buckets\n        boundaries = [mn + step * s for s in range(0, buckets)]\n\n        pipeline[0][\"$facet\"][sub_pipeline] = [\n            {\n                \"$bucket\": {\n                    \"groupBy\": \"$%s\" % k,\n                    \"boundaries\": boundaries,\n                    \"default\": \"null\",\n                    \"output\": {\"count\": {\"$sum\": 1}},\n                }\n            },\n            {\n                \"$group\": {\n                    \"_id\": k,\n                    \"data\": {\n                        \"$push\": {\n                            \"key\": {\n                                \"$cond\": [\n                                    {\"$ne\": [\"$_id\", \"null\"]},\n                                    {\"$add\": [\"$_id\", step / 2]},\n                                    \"null\",\n                                ]\n                            },\n                            \"count\": \"$count\",\n                        }\n                    },\n                }\n            },\n            {\n                \"$project\": {\n                    \"name\": k,\n                    \"type\": v.__class__.__name__[\n                        : -len(\"Field\")  # grab field type from the class\n                    ].lower(),\n                    \"data\": \"$data\",\n                }\n            },\n        ]\n\n\nsocketio.on_namespace(StateController(\"/state\"))\n\n\nif __name__ == \"__main__\":\n    socketio.run(app, debug=True)\n", "path": "fiftyone/server/main.py"}], "after_files": [{"content": "\"\"\"\nFiftyOne Flask server.\n\n| Copyright 2017-2020, Voxel51, Inc.\n| `voxel51.com <https://voxel51.com/>`_\n|\n\"\"\"\n# pragma pylint: disable=redefined-builtin\n# pragma pylint: disable=unused-wildcard-import\n# pragma pylint: disable=wildcard-import\nfrom __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\nfrom builtins import *\n\n# pragma pylint: enable=redefined-builtin\n# pragma pylint: enable=unused-wildcard-import\n# pragma pylint: enable=wildcard-import\n\nimport json\nimport logging\nimport os\n\nfrom bson import json_util\nfrom flask import Flask, request, send_file\nfrom flask_socketio import emit, Namespace, SocketIO\n\nos.environ[\"FIFTYONE_SERVER\"] = \"1\"\nimport fiftyone.core.fields as fof\nimport fiftyone.core.state as fos\n\nfrom util import get_image_size\nfrom pipelines import DISTRIBUTION_PIPELINES, LABELS, SCALARS\n\nlogger = logging.getLogger(__name__)\n\napp = Flask(__name__)\napp.config[\"SECRET_KEY\"] = \"fiftyone\"\n\nsocketio = SocketIO(app, async_mode=\"eventlet\", cors_allowed_origin=\"*\")\n\n\n@app.route(\"/\")\ndef get_sample_media():\n    \"\"\"Gets the sample media.\n\n    Returns:\n        bytes\n    \"\"\"\n    path = request.args.get(\"path\")\n    return send_file(path)\n\n\ndef _load_state(func):\n    def wrapper(self, *args, **kwargs):\n        state = fos.StateDescription.from_dict(self.state)\n        state = func(self, state, *args, **kwargs)\n        self.state = state.serialize()\n        emit(\"update\", self.state, broadcast=True, include_self=False)\n        return self.state\n\n    return wrapper\n\n\nclass StateController(Namespace):\n    \"\"\"State controller.\n\n    Attributes:\n        state: a :class:`fiftyone.core.state.StateDescription` instance\n\n    Args:\n        **args: postional arguments for ``flask_socketio.Namespace``\n        **kwargs: keyword arguments for ``flask_socketio.Namespace``\n    \"\"\"\n\n    def __init__(self, *args, **kwargs):\n        self.state = fos.StateDescription().serialize()\n        super(StateController, self).__init__(*args, **kwargs)\n\n    def on_connect(self):\n        \"\"\"Handles connection to the server.\"\"\"\n        pass\n\n    def on_disconnect(self):\n        \"\"\"Handles disconnection from the server.\"\"\"\n        pass\n\n    def on_update(self, state):\n        \"\"\"Updates the state.\n\n        Args:\n            state: a serialized :class:`fiftyone.core.state.StateDescription`\n        \"\"\"\n        self.state = state\n        emit(\"update\", state, broadcast=True, include_self=False)\n\n    def on_get_current_state(self, _):\n        \"\"\"Gets the current state.\n\n        Returns:\n            a :class:`fiftyone.core.state.StateDescription`\n        \"\"\"\n        return self.state\n\n    @_load_state\n    def on_add_selection(self, state, _id):\n        \"\"\"Adds a sample to the selected samples list.\n\n        Args:\n            state: the current :class:`fiftyone.core.state.StateDescription`\n            _id: the sample ID\n\n        Returns:\n            the updated :class:`fiftyone.core.state.StateDescription`\n        \"\"\"\n        selected = set(state.selected)\n        selected.add(_id)\n        state.selected = list(selected)\n        return state\n\n    @_load_state\n    def on_remove_selection(self, state, _id):\n        \"\"\"Remove a sample from the selected samples list\n\n        Args:\n            state: the current :class:`fiftyone.core.state.StateDescription`\n            _id: the sample ID\n\n        Returns:\n            the updated :class:`fiftyone.core.state.StateDescription`\n        \"\"\"\n        selected = set(state.selected)\n        selected.remove(_id)\n        state.selected = list(selected)\n        return state\n\n    def on_page(self, page, page_length=20):\n        \"\"\"Gets the requested page of samples.\n\n        Args:\n            page: the page number\n            page_length: the page length\n\n        Returns:\n            the list of sample dicts for the page\n        \"\"\"\n        state = fos.StateDescription.from_dict(self.state)\n        if state.view is not None:\n            view = state.view\n        elif state.dataset is not None:\n            view = state.dataset.view()\n        else:\n            return []\n\n        view = view.skip((page - 1) * page_length).limit(page_length + 1)\n        samples = [\n            json.loads(json_util.dumps(s.to_mongo_dict())) for s in view\n        ]\n        more = False\n        if len(samples) > page_length:\n            samples = samples[:page_length]\n            more = page + 1\n\n        results = [{\"sample\": s} for s in samples]\n        for r in results:\n            w, h = get_image_size(r[\"sample\"][\"filepath\"])\n            r[\"width\"] = w\n            r[\"height\"] = h\n\n        return {\"results\": results, \"more\": more}\n\n    def on_lengths(self, _):\n        state = fos.StateDescription.from_dict(self.state)\n        if state.view is not None:\n            view = state.view\n        elif state.dataset is not None:\n            view = state.dataset.view()\n        else:\n            return []\n        return {\"labels\": view.get_label_fields(), \"tags\": view.get_tags()}\n\n    def on_get_distributions(self, group):\n        \"\"\"Gets the distributions for the current state with respect to a group,\n\n        Args:\n            group: one of \"labels\", \"tags\", or \"scalars\"\n\n        Returns:\n            a list of distributions\n        \"\"\"\n        state = fos.StateDescription.from_dict(self.state)\n        if state.view is not None:\n            view = state.view\n        elif state.dataset is not None:\n            view = state.dataset.view()\n        else:\n            return []\n\n        return _get_distributions(view, group)\n\n    def on_get_facets(self, _):\n        \"\"\"Gets the facets for the current state.\n\n        Args:\n            _: the message, which is not used\n\n        Returns:\n            the list of facets\n        \"\"\"\n        state = fos.StateDescription.from_dict(self.state)\n        if state.view is not None:\n            view = state.view\n        elif state.dataset is not None:\n            view = state.dataset.view()\n        else:\n            return []\n\n        return view._get_facets()\n\n    def on_set_facets(self, facets):\n        \"\"\"Sets the facets for the current state.\n\n        Args:\n            facets: the facets string\n        \"\"\"\n        _, value = facets.split(\".\")\n        state = fos.StateDescription.from_dict(self.state)\n        state.view = state.dataset.view().match_tag(value)\n        self.state = state.serialize()\n        emit(\"update\", self.state, broadcast=True, include_self=True)\n\n\ndef _get_distributions(view, group):\n    pipeline = DISTRIBUTION_PIPELINES[group]\n\n    # we add a sub-pipeline for each numeric as it looks like multiple\n    # buckets in a single pipeline is not supported\n    if group == SCALARS:\n        _numeric_distribution_pipelines(view, pipeline)\n\n    result = list(view.aggregate(pipeline))\n\n    if group in {LABELS, SCALARS}:\n        new_result = []\n        for f in result[0].values():\n            new_result += f\n        result = new_result\n\n    if group != SCALARS:\n        for idx, dist in enumerate(result):\n            result[idx][\"data\"] = sorted(\n                result[idx][\"data\"], key=lambda c: c[\"count\"], reverse=True\n            )\n\n    return sorted(result, key=lambda d: d[\"name\"])\n\n\ndef _numeric_bounds(view, numerics):\n    bounds_pipeline = [{\"$facet\": {}}]\n    for idx, (k, v) in enumerate(numerics.items()):\n        bounds_pipeline[0][\"$facet\"][\"numeric-%d\" % idx] = [\n            {\n                \"$group\": {\n                    \"_id\": k,\n                    \"min\": {\"$min\": \"$%s\" % k},\n                    \"max\": {\"$max\": \"$%s\" % k},\n                },\n            }\n        ]\n\n    return list(view.aggregate(bounds_pipeline))[0] if len(numerics) else {}\n\n\ndef _numeric_distribution_pipelines(view, pipeline, buckets=50):\n    numerics = view._dataset.get_field_schema(ftype=fof.IntField)\n    numerics.update(view._dataset.get_field_schema(ftype=fof.FloatField))\n\n    # here we query the min and max for each numeric field\n    # unfortunately, it looks like this has to be a separate query\n    bounds = _numeric_bounds(view, numerics)\n\n    # for each numeric field, build the boundaries array with the\n    # min/max results when adding the field's sub-pipeline\n    for idx, (k, v) in enumerate(numerics.items()):\n        sub_pipeline = \"numeric-%d\" % idx\n        field_bounds = bounds[sub_pipeline][0]\n        mn = field_bounds[\"min\"]\n        mx = field_bounds[\"max\"]\n        step = (mx - mn) / buckets\n        boundaries = [mn + step * s for s in range(0, buckets)]\n\n        pipeline[0][\"$facet\"][sub_pipeline] = [\n            {\n                \"$bucket\": {\n                    \"groupBy\": \"$%s\" % k,\n                    \"boundaries\": boundaries,\n                    \"default\": \"null\",\n                    \"output\": {\"count\": {\"$sum\": 1}},\n                }\n            },\n            {\n                \"$group\": {\n                    \"_id\": k,\n                    \"data\": {\n                        \"$push\": {\n                            \"key\": {\n                                \"$cond\": [\n                                    {\"$ne\": [\"$_id\", \"null\"]},\n                                    {\"$add\": [\"$_id\", step / 2]},\n                                    \"null\",\n                                ]\n                            },\n                            \"count\": \"$count\",\n                        }\n                    },\n                }\n            },\n            {\n                \"$project\": {\n                    \"name\": k,\n                    \"type\": v.__class__.__name__[\n                        : -len(\"Field\")  # grab field type from the class\n                    ].lower(),\n                    \"data\": \"$data\",\n                }\n            },\n        ]\n\n\nsocketio.on_namespace(StateController(\"/state\"))\n\n\nif __name__ == \"__main__\":\n    socketio.run(app, debug=True)\n", "path": "fiftyone/server/main.py"}]}