Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 20fb700

Browse filesBrowse files
authored
Merge pull request #651 from plotly/unify-api
[2.0.0] Unify API
2 parents 8fdd412 + b5311de commit 20fb700
Copy full SHA for 20fb700

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner
Expand file treeCollapse file tree

46 files changed

+2384
-552
lines changed

‎optional-requirements.txt

Copy file name to clipboardExpand all lines: optional-requirements.txt
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ numpy
1212
# matplotlib==1.3.1
1313

1414
## testing dependencies ##
15-
nose
16-
coverage
15+
coverage==4.3.1
16+
mock==2.0.0
17+
nose==1.3.3
1718

1819
## ipython ##
1920
ipython

‎plotly/api/__init__.py

Copy file name to clipboardExpand all lines: plotly/api/__init__.py
Whitespace-only changes.

‎plotly/api/utils.py

Copy file name to clipboard
+41Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from base64 import b64encode
2+
3+
from requests.compat import builtin_str, is_py2
4+
5+
6+
def _to_native_string(string, encoding):
7+
if isinstance(string, builtin_str):
8+
return string
9+
if is_py2:
10+
return string.encode(encoding)
11+
return string.decode(encoding)
12+
13+
14+
def to_native_utf8_string(string):
15+
return _to_native_string(string, 'utf-8')
16+
17+
18+
def to_native_ascii_string(string):
19+
return _to_native_string(string, 'ascii')
20+
21+
22+
def basic_auth(username, password):
23+
"""
24+
Creates the basic auth value to be used in an authorization header.
25+
26+
This is mostly copied from the requests library.
27+
28+
:param (str) username: A Plotly username.
29+
:param (str) password: The password for the given Plotly username.
30+
:returns: (str) An 'authorization' header for use in a request header.
31+
32+
"""
33+
if isinstance(username, str):
34+
username = username.encode('latin1')
35+
36+
if isinstance(password, str):
37+
password = password.encode('latin1')
38+
39+
return 'Basic ' + to_native_ascii_string(
40+
b64encode(b':'.join((username, password))).strip()
41+
)

‎plotly/api/v1/__init__.py

Copy file name to clipboard
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from __future__ import absolute_import
2+
3+
from plotly.api.v1.clientresp import clientresp

‎plotly/api/v1/clientresp.py

Copy file name to clipboard
+44Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
"""Interface to deprecated /clientresp API. Subject to deletion."""
2+
from __future__ import absolute_import
3+
4+
import warnings
5+
6+
from requests.compat import json as _json
7+
8+
from plotly import config, utils, version
9+
from plotly.api.v1.utils import request
10+
11+
12+
def clientresp(data, **kwargs):
13+
"""
14+
Deprecated endpoint, still used because it can parse data out of a plot.
15+
16+
When we get around to forcing users to create grids and then create plots,
17+
we can finally get rid of this.
18+
19+
:param (list) data: The data array from a figure.
20+
21+
"""
22+
creds = config.get_credentials()
23+
cfg = config.get_config()
24+
25+
dumps_kwargs = {'sort_keys': True, 'cls': utils.PlotlyJSONEncoder}
26+
27+
payload = {
28+
'platform': 'python', 'version': version.__version__,
29+
'args': _json.dumps(data, **dumps_kwargs),
30+
'un': creds['username'], 'key': creds['api_key'], 'origin': 'plot',
31+
'kwargs': _json.dumps(kwargs, **dumps_kwargs)
32+
}
33+
34+
url = '{plotly_domain}/clientresp'.format(**cfg)
35+
response = request('post', url, data=payload)
36+
37+
# Old functionality, just keeping it around.
38+
parsed_content = response.json()
39+
if parsed_content.get('warning'):
40+
warnings.warn(parsed_content['warning'])
41+
if parsed_content.get('message'):
42+
print(parsed_content['message'])
43+
44+
return response

‎plotly/api/v1/utils.py

Copy file name to clipboard
+87Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
from __future__ import absolute_import
2+
3+
import requests
4+
from requests.exceptions import RequestException
5+
6+
from plotly import config, exceptions
7+
from plotly.api.utils import basic_auth
8+
9+
10+
def validate_response(response):
11+
"""
12+
Raise a helpful PlotlyRequestError for failed requests.
13+
14+
:param (requests.Response) response: A Response object from an api request.
15+
:raises: (PlotlyRequestError) If the request failed for any reason.
16+
:returns: (None)
17+
18+
"""
19+
content = response.content
20+
status_code = response.status_code
21+
try:
22+
parsed_content = response.json()
23+
except ValueError:
24+
message = content if content else 'No Content'
25+
raise exceptions.PlotlyRequestError(message, status_code, content)
26+
27+
message = ''
28+
if isinstance(parsed_content, dict):
29+
error = parsed_content.get('error')
30+
if error:
31+
message = error
32+
else:
33+
if response.ok:
34+
return
35+
if not message:
36+
message = content if content else 'No Content'
37+
38+
raise exceptions.PlotlyRequestError(message, status_code, content)
39+
40+
41+
def get_headers():
42+
"""
43+
Using session credentials/config, get headers for a v1 API request.
44+
45+
Users may have their own proxy layer and so we free up the `authorization`
46+
header for this purpose (instead adding the user authorization in a new
47+
`plotly-authorization` header). See pull #239.
48+
49+
:returns: (dict) Headers to add to a requests.request call.
50+
51+
"""
52+
headers = {}
53+
creds = config.get_credentials()
54+
proxy_auth = basic_auth(creds['proxy_username'], creds['proxy_password'])
55+
56+
if config.get_config()['plotly_proxy_authorization']:
57+
headers['authorization'] = proxy_auth
58+
59+
return headers
60+
61+
62+
def request(method, url, **kwargs):
63+
"""
64+
Central place to make any v1 api request.
65+
66+
:param (str) method: The request method ('get', 'put', 'delete', ...).
67+
:param (str) url: The full api url to make the request to.
68+
:param kwargs: These are passed along to requests.
69+
:return: (requests.Response) The response directly from requests.
70+
71+
"""
72+
if kwargs.get('json', None) is not None:
73+
# See plotly.api.v2.utils.request for examples on how to do this.
74+
raise exceptions.PlotlyError('V1 API does not handle arbitrary json.')
75+
kwargs['headers'] = dict(kwargs.get('headers', {}), **get_headers())
76+
kwargs['verify'] = config.get_config()['plotly_ssl_verification']
77+
try:
78+
response = requests.request(method, url, **kwargs)
79+
except RequestException as e:
80+
# The message can be an exception. E.g., MaxRetryError.
81+
message = str(getattr(e, 'message', 'No message'))
82+
response = getattr(e, 'response', None)
83+
status_code = response.status_code if response else None
84+
content = response.content if response else 'No content'
85+
raise exceptions.PlotlyRequestError(message, status_code, content)
86+
validate_response(response)
87+
return response

‎plotly/api/v2/__init__.py

Copy file name to clipboard
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from __future__ import absolute_import
2+
3+
from plotly.api.v2 import files, folders, grids, images, plot_schema, plots

‎plotly/api/v2/files.py

Copy file name to clipboard
+85Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
"""Interface to Plotly's /v2/files endpoints."""
2+
from __future__ import absolute_import
3+
4+
from plotly.api.v2.utils import build_url, make_params, request
5+
6+
RESOURCE = 'files'
7+
8+
9+
def retrieve(fid, share_key=None):
10+
"""
11+
Retrieve a general file from Plotly.
12+
13+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
14+
:param (str) share_key: The secret key granting 'read' access if private.
15+
:returns: (requests.Response) Returns response directly from requests.
16+
17+
"""
18+
url = build_url(RESOURCE, id=fid)
19+
params = make_params(share_key=share_key)
20+
return request('get', url, params=params)
21+
22+
23+
def update(fid, body):
24+
"""
25+
Update a general file from Plotly.
26+
27+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
28+
:param (dict) body: A mapping of body param names to values.
29+
:returns: (requests.Response) Returns response directly from requests.
30+
31+
"""
32+
url = build_url(RESOURCE, id=fid)
33+
return request('put', url, json=body)
34+
35+
36+
def trash(fid):
37+
"""
38+
Soft-delete a general file from Plotly. (Can be undone with 'restore').
39+
40+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
41+
:returns: (requests.Response) Returns response directly from requests.
42+
43+
"""
44+
url = build_url(RESOURCE, id=fid, route='trash')
45+
return request('post', url)
46+
47+
48+
def restore(fid):
49+
"""
50+
Restore a trashed, general file from Plotly. See 'trash'.
51+
52+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
53+
:returns: (requests.Response) Returns response directly from requests.
54+
55+
"""
56+
url = build_url(RESOURCE, id=fid, route='restore')
57+
return request('post', url)
58+
59+
60+
def permanent_delete(fid):
61+
"""
62+
Permanently delete a trashed, general file from Plotly. See 'trash'.
63+
64+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
65+
:returns: (requests.Response) Returns response directly from requests.
66+
67+
"""
68+
url = build_url(RESOURCE, id=fid, route='permanent_delete')
69+
return request('delete', url)
70+
71+
72+
def lookup(path, parent=None, user=None, exists=None):
73+
"""
74+
Retrieve a general file from Plotly without needing a fid.
75+
76+
:param (str) path: The '/'-delimited path specifying the file location.
77+
:param (int) parent: Parent id, an integer, which the path is relative to.
78+
:param (str) user: The username to target files for. Defaults to requestor.
79+
:param (bool) exists: If True, don't return the full file, just a flag.
80+
:returns: (requests.Response) Returns response directly from requests.
81+
82+
"""
83+
url = build_url(RESOURCE, route='lookup')
84+
params = make_params(path=path, parent=parent, user=user, exists=exists)
85+
return request('get', url, params=params)

‎plotly/api/v2/folders.py

Copy file name to clipboard
+103Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""Interface to Plotly's /v2/folders endpoints."""
2+
from __future__ import absolute_import
3+
4+
from plotly.api.v2.utils import build_url, make_params, request
5+
6+
RESOURCE = 'folders'
7+
8+
9+
def create(body):
10+
"""
11+
Create a new folder.
12+
13+
:param (dict) body: A mapping of body param names to values.
14+
:returns: (requests.Response) Returns response directly from requests.
15+
16+
"""
17+
url = build_url(RESOURCE)
18+
return request('post', url, json=body)
19+
20+
21+
def retrieve(fid, share_key=None):
22+
"""
23+
Retrieve a folder from Plotly.
24+
25+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
26+
:param (str) share_key: The secret key granting 'read' access if private.
27+
:returns: (requests.Response) Returns response directly from requests.
28+
29+
"""
30+
url = build_url(RESOURCE, id=fid)
31+
params = make_params(share_key=share_key)
32+
return request('get', url, params=params)
33+
34+
35+
def update(fid, body):
36+
"""
37+
Update a folder from Plotly.
38+
39+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
40+
:param (dict) body: A mapping of body param names to values.
41+
:returns: (requests.Response) Returns response directly from requests.
42+
43+
"""
44+
url = build_url(RESOURCE, id=fid)
45+
return request('put', url, json=body)
46+
47+
48+
def trash(fid):
49+
"""
50+
Soft-delete a folder from Plotly. (Can be undone with 'restore').
51+
52+
This action is recursively done on files inside the folder.
53+
54+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
55+
:returns: (requests.Response) Returns response directly from requests.
56+
57+
"""
58+
url = build_url(RESOURCE, id=fid, route='trash')
59+
return request('post', url)
60+
61+
62+
def restore(fid):
63+
"""
64+
Restore a trashed folder from Plotly. See 'trash'.
65+
66+
This action is recursively done on files inside the folder.
67+
68+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
69+
:returns: (requests.Response) Returns response directly from requests.
70+
71+
"""
72+
url = build_url(RESOURCE, id=fid, route='restore')
73+
return request('post', url)
74+
75+
76+
def permanent_delete(fid):
77+
"""
78+
Permanently delete a trashed folder file from Plotly. See 'trash'.
79+
80+
This action is recursively done on files inside the folder.
81+
82+
:param (str) fid: The `{username}:{idlocal}` identifier. E.g. `foo:88`.
83+
:returns: (requests.Response) Returns response directly from requests.
84+
85+
"""
86+
url = build_url(RESOURCE, id=fid, route='permanent_delete')
87+
return request('delete', url)
88+
89+
90+
def lookup(path, parent=None, user=None, exists=None):
91+
"""
92+
Retrieve a folder file from Plotly without needing a fid.
93+
94+
:param (str) path: The '/'-delimited path specifying the file location.
95+
:param (int) parent: Parent id, an integer, which the path is relative to.
96+
:param (str) user: The username to target files for. Defaults to requestor.
97+
:param (bool) exists: If True, don't return the full file, just a flag.
98+
:returns: (requests.Response) Returns response directly from requests.
99+
100+
"""
101+
url = build_url(RESOURCE, route='lookup')
102+
params = make_params(path=path, parent=parent, user=user, exists=exists)
103+
return request('get', url, params=params)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.