From ce5483093c796fc351fe0de2f1fe162eebebb7fd Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 16:00:12 -0400 Subject: [PATCH 01/22] add SSL support for streaming --- plotly/plotly/plotly.py | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/plotly/plotly/plotly.py b/plotly/plotly/plotly.py index c175e7c7d7a..43191e9c379 100644 --- a/plotly/plotly/plotly.py +++ b/plotly/plotly/plotly.py @@ -27,6 +27,7 @@ import six.moves from requests.auth import HTTPBasicAuth +from urlparse import urlparse from plotly import exceptions, tools, utils, version, files from plotly.plotly import chunked_requests @@ -439,6 +440,9 @@ class Stream: """ + HTTP_PORT = 80 + HTTPS_PORT = 443 + @utils.template_doc(**tools.get_config_file()) def __init__(self, stream_id): """ @@ -454,6 +458,29 @@ def __init__(self, stream_id): self.connected = False 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_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 = 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, + 'headers': headers + } + + return streaming_specs + def heartbeat(self, reconnect_on=(200, '', 408)): """ Keep stream alive. Streams will close after ~1 min of inactivity. @@ -481,10 +508,8 @@ def open(self): https://plot.ly/python/streaming/ """ - streaming_url = get_config()['plotly_streaming_domain'] - self._stream = chunked_requests.Stream( - streaming_url, 80, {'Host': streaming_url, - 'plotly-streamtoken': self.stream_id}) + streaming_specs = self.get_streaming_specs() + self._stream = chunked_requests.Stream(**streaming_specs) def write(self, trace, layout=None, validate=True, reconnect_on=(200, '', 408)): From 5834a124e8293ebf4d21d40f00944158943c3acc Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 16:00:31 -0400 Subject: [PATCH 02/22] add tests for streaming over https --- .../test_core/test_stream/test_stream.py | 62 ++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/plotly/tests/test_core/test_stream/test_stream.py b/plotly/tests/test_core/test_stream/test_stream.py index c36c91599f8..a5c648dd9ee 100644 --- a/plotly/tests/test_core/test_stream/test_stream.py +++ b/plotly/tests/test_core/test_stream/test_stream.py @@ -10,7 +10,7 @@ import time from nose.plugins.attrib import attr -from nose.tools import raises +from nose.tools import raises, eq_ import plotly.plotly as py from plotly.graph_objs import (Layout, Scatter, Stream) @@ -123,3 +123,63 @@ def test_stream_unstreamable(): my_stream.open() my_stream.write(Scatter(x=1, y=10, name='nope')) my_stream.close() + + +def test_stream_no_scheme(): + + # If no scheme is used in the plotly_streaming_domain, port 80 + # should be used for streaming and ssl_enabled should be False + + py.sign_in(un, ak, **{'plotly_streaming_domain': 'stream.plot.ly'}) + my_stream = py.Stream(tk) + expected_streaming_specs = { + 'server': 'stream.plot.ly', + 'port': 80, + 'ssl_enabled': False, + 'headers': { + 'Host': 'stream.plot.ly', + 'plotly-streamtoken': tk + } + } + actual_streaming_specs = my_stream.get_streaming_specs() + eq_(expected_streaming_specs, actual_streaming_specs) + + +def test_stream_http(): + + # If the http scheme is used in the plotly_streaming_domain, port 80 + # should be used for streaming and ssl_enabled should be False + + py.sign_in(un, ak, **{'plotly_streaming_domain': 'http://stream.plot.ly'}) + my_stream = py.Stream(tk) + expected_streaming_specs = { + 'server': 'stream.plot.ly', + 'port': 80, + 'ssl_enabled': False, + 'headers': { + 'Host': 'stream.plot.ly', + 'plotly-streamtoken': tk + } + } + actual_streaming_specs = my_stream.get_streaming_specs() + eq_(expected_streaming_specs, actual_streaming_specs) + + +def test_stream_https(): + + # If the https scheme is used in the plotly_streaming_domain, port 443 + # should be used for streaming and ssl_enabled should be True + + py.sign_in(un, ak, **{'plotly_streaming_domain': 'https://stream.plot.ly'}) + my_stream = py.Stream(tk) + expected_streaming_specs = { + 'server': 'stream.plot.ly', + 'port': 443, + 'ssl_enabled': True, + 'headers': { + 'Host': 'stream.plot.ly', + 'plotly-streamtoken': tk + } + } + actual_streaming_specs = my_stream.get_streaming_specs() + eq_(expected_streaming_specs, actual_streaming_specs) \ No newline at end of file From a4616e3c90d3993570aaa638aa87e5cd14c9d529 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 18:13:50 -0400 Subject: [PATCH 03/22] version update --- plotly/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotly/version.py b/plotly/version.py index ad78fc163b8..b6c0149dc78 100644 --- a/plotly/version.py +++ b/plotly/version.py @@ -1,2 +1,2 @@ -__version__ = '1.9.11' +__version__ = '1.1.0' From 01f1c467f53c33ed8a5f4b5eb5376ede41fe2340 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 18:19:40 -0400 Subject: [PATCH 04/22] update changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f00262c9b56..2109a5073e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [1.1.0] - 2016-05-16 +### Added +SSL support for streaming. Requires the SSL module, which was backported in +Python v2.7.9, via chunked_requests submodule. + ## [1.9.11] - 2016-05-02 ### Added - The FigureFactory can now create scatter plot matrices with `.create_scatterplotmatrix`. Check it out with: From f46ef5f18e5e875858342793eee4ce51ff7e8545 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 18:25:45 -0400 Subject: [PATCH 05/22] version fix --- plotly/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotly/version.py b/plotly/version.py index b6c0149dc78..eed855dc752 100644 --- a/plotly/version.py +++ b/plotly/version.py @@ -1,2 +1,2 @@ -__version__ = '1.1.0' +__version__ = '1.10.0' From 4a2c82ec317683e2403d33e174ede6fae02ad060 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 18:36:18 -0400 Subject: [PATCH 06/22] fix version 1.1.0 ---> 1.10.0 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2109a5073e1..e5d83b85745 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -## [1.1.0] - 2016-05-16 +## [1.10.0] - 2016-05-16 ### Added SSL support for streaming. Requires the SSL module, which was backported in Python v2.7.9, via chunked_requests submodule. From bf10b6c2f13a4e9afd3ddf6bac111359c93cf9e6 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 18:42:53 -0400 Subject: [PATCH 07/22] fix missing newline --- plotly/tests/test_core/test_stream/test_stream.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plotly/tests/test_core/test_stream/test_stream.py b/plotly/tests/test_core/test_stream/test_stream.py index a5c648dd9ee..18b7b8b9660 100644 --- a/plotly/tests/test_core/test_stream/test_stream.py +++ b/plotly/tests/test_core/test_stream/test_stream.py @@ -182,4 +182,4 @@ def test_stream_https(): } } actual_streaming_specs = my_stream.get_streaming_specs() - eq_(expected_streaming_specs, actual_streaming_specs) \ No newline at end of file + eq_(expected_streaming_specs, actual_streaming_specs) From e60d30cda15b0d75a73818e394e19af2592e521b Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 19:02:39 -0400 Subject: [PATCH 08/22] use six for urllib for compat with Python 3 --- plotly/plotly/plotly.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plotly/plotly/plotly.py b/plotly/plotly/plotly.py index 43191e9c379..9effa9e4e57 100644 --- a/plotly/plotly/plotly.py +++ b/plotly/plotly/plotly.py @@ -469,7 +469,8 @@ def get_streaming_specs(self): # If no scheme (https/https) is included in the streaming_url, the # host will be None. Use streaming_url in this case. - host = urlparse(streaming_url).hostname or streaming_url + host = (six.moves.urllib.parse.urlparse(streaming_url).hostname or + streaming_url) headers = {'Host': host, 'plotly-streamtoken': self.stream_id} streaming_specs = { From d4b60cd5046ce1ff0f01a0bdf158f5f1ae267651 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 19:04:51 -0400 Subject: [PATCH 09/22] remove unused import --- plotly/plotly/plotly.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plotly/plotly/plotly.py b/plotly/plotly/plotly.py index 9effa9e4e57..15b2e3f011d 100644 --- a/plotly/plotly/plotly.py +++ b/plotly/plotly/plotly.py @@ -27,7 +27,6 @@ import six.moves from requests.auth import HTTPBasicAuth -from urlparse import urlparse from plotly import exceptions, tools, utils, version, files from plotly.plotly import chunked_requests From ff7a57dd2faaeba12a1fe9da7a7e26a7562a8148 Mon Sep 17 00:00:00 2001 From: Andrew Seier Date: Mon, 16 May 2016 16:46:16 -0700 Subject: [PATCH 10/22] Run `make pull_chunked` and `make sync_chunked`. --- .../chunked_requests/chunked_request.py | 43 +++++++++++++++---- submodules/chunked_requests | 2 +- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/plotly/plotly/chunked_requests/chunked_request.py b/plotly/plotly/chunked_requests/chunked_request.py index c154ec8635d..66676c3aedd 100644 --- a/plotly/plotly/chunked_requests/chunked_request.py +++ b/plotly/plotly/chunked_requests/chunked_request.py @@ -3,10 +3,12 @@ import os from six.moves import http_client from six.moves.urllib.parse import urlparse +from ssl import SSLWantReadError + class Stream: - def __init__(self, server, port=80, headers={}, url='/'): - ''' Initialize a stream object and an HTTP Connection + def __init__(self, server, port=80, headers={}, url='/', ssl_enabled=False): + ''' Initialize a stream object and an HTTP or HTTPS connection with chunked Transfer-Encoding to server:port with optional headers. ''' self.maxtries = 5 @@ -17,6 +19,7 @@ def __init__(self, server, port=80, headers={}, url='/'): self._port = port self._headers = headers self._url = url + self._ssl_enabled = ssl_enabled self._connect() def write(self, data, reconnect_on=('', 200, )): @@ -73,17 +76,21 @@ def write(self, data, reconnect_on=('', 200, )): 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 + the appropriate proxy_server and proxy_port. Assumes https_proxy is used + when ssl_enabled=True. """ proxy_server = None proxy_port = None + ssl_enabled = self._ssl_enabled - ## only doing HTTPConnection, so only use http_proxy - proxy = os.environ.get("http_proxy") + if ssl_enabled: + proxy = os.environ.get("https_proxy") + else: + proxy = os.environ.get("http_proxy") no_proxy = os.environ.get("no_proxy") - no_proxy_url = no_proxy and self._url in no_proxy + no_proxy_url = no_proxy and self._server in no_proxy if proxy and not no_proxy_url: p = urlparse(proxy) @@ -93,19 +100,30 @@ def _get_proxy_config(self): return proxy_server, proxy_port def _connect(self): - ''' Initialize an HTTP connection with chunked Transfer-Encoding + ''' 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 = self._get_proxy_config() if (proxy_server and proxy_port): - self._conn = http_client.HTTPConnection(proxy_server, proxy_port) + if ssl_enabled: + self._conn = http_client.HTTPSConnection( + proxy_server, proxy_port + ) + else: + self._conn = http_client.HTTPConnection( + proxy_server, proxy_port + ) self._conn.set_tunnel(server, port) else: - self._conn = http_client.HTTPConnection(server, port) + if ssl_enabled: + self._conn = http_client.HTTPSConnection(server, port) + else: + self._conn = http_client.HTTPConnection(server, port) self._conn.putrequest('POST', self._url) self._conn.putheader('Transfer-Encoding', 'chunked') @@ -236,6 +254,13 @@ def _isconnected(self): # let's just assume that we're still connected and # hopefully recieve some data on the next try. return True + elif isinstance(e, SSLWantReadError): + # From: https://docs.python.org/3/library/ssl.html + # This is raised 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. The socket is still + # connected to the server in this case. + return True else: # Unknown scenario raise e diff --git a/submodules/chunked_requests b/submodules/chunked_requests index f940b023110..e503f639413 160000 --- a/submodules/chunked_requests +++ b/submodules/chunked_requests @@ -1 +1 @@ -Subproject commit f940b023110a77bbaf79f9dbccca701cf756335f +Subproject commit e503f639413a273f270db0fb2345437f43a55345 From f1ba31b6848ca48e8ecf2511688e55e910263af0 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 19:56:12 -0400 Subject: [PATCH 11/22] update python version for tests --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 3c146d51ecc..e207ab477fe 100644 --- a/circle.yml +++ b/circle.yml @@ -4,7 +4,7 @@ machine: PLOTLY_PACKAGE_ROOT: /home/ubuntu/${CIRCLE_PROJECT_REPONAME} PLOTLY_CONFIG_DIR: ${HOME}/.plotly - PLOTLY_PYTHON_VERSIONS: 2.7.8 3.3.3 3.4.1 + PLOTLY_PYTHON_VERSIONS: 2.7.9 3.3.3 3.4.1 PLOTLY_CORE_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/requirements.txt PLOTLY_OPTIONAL_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/optional-requirements.txt From c71d4ce670269781cd554223a3c6707ed1068556 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 19:58:10 -0400 Subject: [PATCH 12/22] update python to latest --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index e207ab477fe..a6e65dde535 100644 --- a/circle.yml +++ b/circle.yml @@ -4,7 +4,7 @@ machine: PLOTLY_PACKAGE_ROOT: /home/ubuntu/${CIRCLE_PROJECT_REPONAME} PLOTLY_CONFIG_DIR: ${HOME}/.plotly - PLOTLY_PYTHON_VERSIONS: 2.7.9 3.3.3 3.4.1 + PLOTLY_PYTHON_VERSIONS: 2.7.11 3.3.3 3.4.1 PLOTLY_CORE_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/requirements.txt PLOTLY_OPTIONAL_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/optional-requirements.txt From 2d08352c23fb993bf52a52e9883535fdbe338a19 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 20:18:19 -0400 Subject: [PATCH 13/22] use 2.7.10 (2.7.11 not available in circle yet) --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index a6e65dde535..4839c19c853 100644 --- a/circle.yml +++ b/circle.yml @@ -4,7 +4,7 @@ machine: PLOTLY_PACKAGE_ROOT: /home/ubuntu/${CIRCLE_PROJECT_REPONAME} PLOTLY_CONFIG_DIR: ${HOME}/.plotly - PLOTLY_PYTHON_VERSIONS: 2.7.11 3.3.3 3.4.1 + PLOTLY_PYTHON_VERSIONS: 2.7.10 3.3.3 3.4.1 PLOTLY_CORE_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/requirements.txt PLOTLY_OPTIONAL_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/optional-requirements.txt From d9989efe58c6ae381ea514eb730d078ebc5db063 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 21:44:11 -0400 Subject: [PATCH 14/22] increase timeout to 1hr --- circle.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 4839c19c853..bf49b74c8f0 100644 --- a/circle.yml +++ b/circle.yml @@ -13,8 +13,9 @@ dependencies: override: # run all the pre-written installers (this will take a *while*) - - bash circle/setup.sh - + # todo: remove timeout (revert to default of 600s) + - bash circle/setup.sh: + timeout: 3600 # install testing tools for circle's version of things - pip install nose coverage - pip install -I . From f8c2f464258f786c5bb95f4d18ccbdc2a9c55fdd Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 21:51:35 -0400 Subject: [PATCH 15/22] fix indentation --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index bf49b74c8f0..ed2fe3c063e 100644 --- a/circle.yml +++ b/circle.yml @@ -15,7 +15,7 @@ dependencies: # run all the pre-written installers (this will take a *while*) # todo: remove timeout (revert to default of 600s) - bash circle/setup.sh: - timeout: 3600 + timeout: 3600 # install testing tools for circle's version of things - pip install nose coverage - pip install -I . From 897565e380e294ac95b0617f03711975bd5baac6 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 22:09:47 -0400 Subject: [PATCH 16/22] go back to using 2.8 (2.9 no longer required) --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index ed2fe3c063e..70fa7dbf147 100644 --- a/circle.yml +++ b/circle.yml @@ -4,7 +4,7 @@ machine: PLOTLY_PACKAGE_ROOT: /home/ubuntu/${CIRCLE_PROJECT_REPONAME} PLOTLY_CONFIG_DIR: ${HOME}/.plotly - PLOTLY_PYTHON_VERSIONS: 2.7.10 3.3.3 3.4.1 + PLOTLY_PYTHON_VERSIONS: 2.7.8 3.3.3 3.4.1 PLOTLY_CORE_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/requirements.txt PLOTLY_OPTIONAL_REQUIREMENTS_FILE: ${PLOTLY_PACKAGE_ROOT}/optional-requirements.txt From e873d67343ed33e24b04ad1f648d5beb0cbd1c4b Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 22:09:57 -0400 Subject: [PATCH 17/22] remove timeout --- circle.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/circle.yml b/circle.yml index 70fa7dbf147..a38eb038c1c 100644 --- a/circle.yml +++ b/circle.yml @@ -13,9 +13,7 @@ dependencies: override: # run all the pre-written installers (this will take a *while*) - # todo: remove timeout (revert to default of 600s) - bash circle/setup.sh: - timeout: 3600 # install testing tools for circle's version of things - pip install nose coverage - pip install -I . From f0e8a5e8fe72f380a20a6c965b1c74ae91a0d785 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Mon, 16 May 2016 22:16:02 -0400 Subject: [PATCH 18/22] fix circle template --- circle.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index a38eb038c1c..7efa2a1502d 100644 --- a/circle.yml +++ b/circle.yml @@ -13,7 +13,8 @@ dependencies: override: # run all the pre-written installers (this will take a *while*) - - bash circle/setup.sh: + - bash circle/setup.sh + # install testing tools for circle's version of things - pip install nose coverage - pip install -I . From 66db06d08d80d3b769b125c1767c4fe9d82cde7a Mon Sep 17 00:00:00 2001 From: Andrew Seier Date: Mon, 16 May 2016 19:29:07 -0700 Subject: [PATCH 19/22] Run `make pull_chunked` and `make sync_chunked`. This makes us compatible with Python < 2.7.9 again. --- .../chunked_requests/chunked_request.py | 19 +++++++++++-------- submodules/chunked_requests | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/plotly/plotly/chunked_requests/chunked_request.py b/plotly/plotly/chunked_requests/chunked_request.py index 66676c3aedd..c0be184a7a8 100644 --- a/plotly/plotly/chunked_requests/chunked_request.py +++ b/plotly/plotly/chunked_requests/chunked_request.py @@ -3,7 +3,7 @@ import os from six.moves import http_client from six.moves.urllib.parse import urlparse -from ssl import SSLWantReadError +from ssl import SSLError class Stream: @@ -254,13 +254,16 @@ def _isconnected(self): # let's just assume that we're still connected and # hopefully recieve some data on the next try. return True - elif isinstance(e, SSLWantReadError): - # From: https://docs.python.org/3/library/ssl.html - # This is raised 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. The socket is still - # connected to the server in this case. - return True + elif isinstance(e, 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 diff --git a/submodules/chunked_requests b/submodules/chunked_requests index e503f639413..42799319b8f 160000 --- a/submodules/chunked_requests +++ b/submodules/chunked_requests @@ -1 +1 @@ -Subproject commit e503f639413a273f270db0fb2345437f43a55345 +Subproject commit 42799319b8f06ce89a3831b3ff911207ca0b6a02 From 3c7a623e160bbea153d04e22ef54bc8775d03177 Mon Sep 17 00:00:00 2001 From: Andrew Seier Date: Mon, 16 May 2016 16:02:57 -0700 Subject: [PATCH 20/22] Use `TestCase` in `test_stream.py` tests. --- .../test_core/test_stream/test_stream.py | 313 +++++++++--------- 1 file changed, 152 insertions(+), 161 deletions(-) diff --git a/plotly/tests/test_core/test_stream/test_stream.py b/plotly/tests/test_core/test_stream/test_stream.py index 18b7b8b9660..2e0a1131010 100644 --- a/plotly/tests/test_core/test_stream/test_stream.py +++ b/plotly/tests/test_core/test_stream/test_stream.py @@ -1,16 +1,13 @@ """ -test_get_figure: -================= - -A module intended for use with Nose. +Streaming tests. """ from __future__ import absolute_import import time +from unittest import TestCase from nose.plugins.attrib import attr -from nose.tools import raises, eq_ import plotly.plotly as py from plotly.graph_objs import (Layout, Scatter, Stream) @@ -24,162 +21,156 @@ 'plotly_api_domain': 'https://api.plot.ly'} -def setUp(): - py.sign_in(un, ak, **config) - - -@attr('slow') -def test_initialize_stream_plot(): - py.sign_in(un, ak) - stream = Stream(token=tk, maxpoints=50) - url = py.plot([Scatter(x=[], y=[], mode='markers', stream=stream)], - auto_open=False, - world_readable=True, - filename='stream-test') - assert url == 'https://plot.ly/~PythonAPI/461' - time.sleep(.5) - - -@attr('slow') -def test_stream_single_points(): - py.sign_in(un, ak) - stream = Stream(token=tk, maxpoints=50) - res = py.plot([Scatter(x=[], y=[], mode='markers', stream=stream)], - auto_open=False, - world_readable=True, - filename='stream-test') - time.sleep(.5) - my_stream = py.Stream(tk) - my_stream.open() - my_stream.write(Scatter(x=1, y=10)) - time.sleep(.5) - my_stream.close() - - -@attr('slow') -def test_stream_multiple_points(): - py.sign_in(un, ak) - stream = Stream(token=tk, maxpoints=50) - url = py.plot([Scatter(x=[], y=[], mode='markers', stream=stream)], - auto_open=False, - world_readable=True, - filename='stream-test') - time.sleep(.5) - my_stream = py.Stream(tk) - my_stream.open() - my_stream.write(Scatter(x=[1, 2, 3, 4], y=[2, 1, 2, 5])) - time.sleep(.5) - my_stream.close() - - -@attr('slow') -def test_stream_layout(): - py.sign_in(un, ak) - stream = Stream(token=tk, maxpoints=50) - url = py.plot([Scatter(x=[], y=[], mode='markers', stream=stream)], - auto_open=False, - world_readable=True, - filename='stream-test') - time.sleep(.5) - title_0 = "some title i picked first" - title_1 = "this other title i picked second" - my_stream = py.Stream(tk) - my_stream.open() - my_stream.write(Scatter(x=1, y=10), layout=Layout(title=title_0)) - time.sleep(.5) - my_stream.close() - my_stream.open() - my_stream.write(Scatter(x=1, y=10), layout=Layout(title=title_1)) - my_stream.close() - - -@attr('slow') -@raises(exceptions.PlotlyError) -def test_stream_validate_data(): - py.sign_in(un, ak) - my_stream = py.Stream(tk) - my_stream.open() - my_stream.write(dict(x=1, y=10, z=[1])) # assumes scatter... - my_stream.close() - - -@attr('slow') -@raises(exceptions.PlotlyError) -def test_stream_validate_layout(): - py.sign_in(un, ak) - my_stream = py.Stream(tk) - my_stream.open() - my_stream.write(Scatter(x=1, y=10), layout=Layout(legend=True)) - my_stream.close() - - -@attr('slow') -def test_stream_unstreamable(): - - # even though `name` isn't streamable, we don't validate it --> should pass - - py.sign_in(un, ak) - my_stream = py.Stream(tk) - my_stream.open() - my_stream.write(Scatter(x=1, y=10, name='nope')) - my_stream.close() - - -def test_stream_no_scheme(): - - # If no scheme is used in the plotly_streaming_domain, port 80 - # should be used for streaming and ssl_enabled should be False - - py.sign_in(un, ak, **{'plotly_streaming_domain': 'stream.plot.ly'}) - my_stream = py.Stream(tk) - expected_streaming_specs = { - 'server': 'stream.plot.ly', - 'port': 80, - 'ssl_enabled': False, - 'headers': { - 'Host': 'stream.plot.ly', - 'plotly-streamtoken': tk +class TestStreaming(TestCase): + + def setUp(self): + py.sign_in(un, ak, **config) + + @attr('slow') + def test_initialize_stream_plot(self): + py.sign_in(un, ak) + stream = Stream(token=tk, maxpoints=50) + url = py.plot([Scatter(x=[], y=[], mode='markers', stream=stream)], + auto_open=False, + world_readable=True, + filename='stream-test') + assert url == 'https://plot.ly/~PythonAPI/461' + time.sleep(.5) + + @attr('slow') + def test_stream_single_points(self): + py.sign_in(un, ak) + stream = Stream(token=tk, maxpoints=50) + res = py.plot([Scatter(x=[], y=[], mode='markers', stream=stream)], + auto_open=False, + world_readable=True, + filename='stream-test') + time.sleep(.5) + my_stream = py.Stream(tk) + my_stream.open() + my_stream.write(Scatter(x=1, y=10)) + time.sleep(.5) + my_stream.close() + + @attr('slow') + def test_stream_multiple_points(self): + py.sign_in(un, ak) + stream = Stream(token=tk, maxpoints=50) + url = py.plot([Scatter(x=[], y=[], mode='markers', stream=stream)], + auto_open=False, + world_readable=True, + filename='stream-test') + time.sleep(.5) + my_stream = py.Stream(tk) + my_stream.open() + my_stream.write(Scatter(x=[1, 2, 3, 4], y=[2, 1, 2, 5])) + time.sleep(.5) + my_stream.close() + + @attr('slow') + def test_stream_layout(self): + py.sign_in(un, ak) + stream = Stream(token=tk, maxpoints=50) + url = py.plot([Scatter(x=[], y=[], mode='markers', stream=stream)], + auto_open=False, + world_readable=True, + filename='stream-test') + time.sleep(.5) + title_0 = "some title i picked first" + title_1 = "this other title i picked second" + my_stream = py.Stream(tk) + my_stream.open() + my_stream.write(Scatter(x=1, y=10), layout=Layout(title=title_0)) + time.sleep(.5) + my_stream.close() + my_stream.open() + my_stream.write(Scatter(x=1, y=10), layout=Layout(title=title_1)) + my_stream.close() + + @attr('slow') + def test_stream_validate_data(self): + with self.assertRaises(exceptions.PlotlyError): + py.sign_in(un, ak) + my_stream = py.Stream(tk) + my_stream.open() + my_stream.write(dict(x=1, y=10, z=[1])) # assumes scatter... + my_stream.close() + + @attr('slow') + def test_stream_validate_layout(self): + with self.assertRaises(exceptions.PlotlyError): + py.sign_in(un, ak) + my_stream = py.Stream(tk) + my_stream.open() + my_stream.write(Scatter(x=1, y=10), layout=Layout(legend=True)) + my_stream.close() + + @attr('slow') + def test_stream_unstreamable(self): + + # even though `name` isn't streamable, we don't validate it --> pass + + py.sign_in(un, ak) + my_stream = py.Stream(tk) + my_stream.open() + my_stream.write(Scatter(x=1, y=10, name='nope')) + my_stream.close() + + def test_stream_no_scheme(self): + + # If no scheme is used in the plotly_streaming_domain, port 80 + # should be used for streaming and ssl_enabled should be False + + py.sign_in(un, ak, **{'plotly_streaming_domain': 'stream.plot.ly'}) + my_stream = py.Stream(tk) + expected_streaming_specs = { + 'server': 'stream.plot.ly', + 'port': 80, + 'ssl_enabled': False, + 'headers': { + 'Host': 'stream.plot.ly', + 'plotly-streamtoken': tk + } } - } - actual_streaming_specs = my_stream.get_streaming_specs() - eq_(expected_streaming_specs, actual_streaming_specs) - - -def test_stream_http(): - - # If the http scheme is used in the plotly_streaming_domain, port 80 - # should be used for streaming and ssl_enabled should be False - - py.sign_in(un, ak, **{'plotly_streaming_domain': 'http://stream.plot.ly'}) - my_stream = py.Stream(tk) - expected_streaming_specs = { - 'server': 'stream.plot.ly', - 'port': 80, - 'ssl_enabled': False, - 'headers': { - 'Host': 'stream.plot.ly', - 'plotly-streamtoken': tk + actual_streaming_specs = my_stream.get_streaming_specs() + self.assertEqual(expected_streaming_specs, actual_streaming_specs) + + def test_stream_http(self): + + # If the http scheme is used in the plotly_streaming_domain, port 80 + # should be used for streaming and ssl_enabled should be False + + py.sign_in(un, ak, + **{'plotly_streaming_domain': 'http://stream.plot.ly'}) + my_stream = py.Stream(tk) + expected_streaming_specs = { + 'server': 'stream.plot.ly', + 'port': 80, + 'ssl_enabled': False, + 'headers': { + 'Host': 'stream.plot.ly', + 'plotly-streamtoken': tk + } } - } - actual_streaming_specs = my_stream.get_streaming_specs() - eq_(expected_streaming_specs, actual_streaming_specs) - - -def test_stream_https(): - - # If the https scheme is used in the plotly_streaming_domain, port 443 - # should be used for streaming and ssl_enabled should be True - - py.sign_in(un, ak, **{'plotly_streaming_domain': 'https://stream.plot.ly'}) - my_stream = py.Stream(tk) - expected_streaming_specs = { - 'server': 'stream.plot.ly', - 'port': 443, - 'ssl_enabled': True, - 'headers': { - 'Host': 'stream.plot.ly', - 'plotly-streamtoken': tk + actual_streaming_specs = my_stream.get_streaming_specs() + self.assertEqual(expected_streaming_specs, actual_streaming_specs) + + def test_stream_https(self): + + # If the https scheme is used in the plotly_streaming_domain, port 443 + # should be used for streaming and ssl_enabled should be True + + py.sign_in(un, ak, + **{'plotly_streaming_domain': 'https://stream.plot.ly'}) + my_stream = py.Stream(tk) + expected_streaming_specs = { + 'server': 'stream.plot.ly', + 'port': 443, + 'ssl_enabled': True, + 'headers': { + 'Host': 'stream.plot.ly', + 'plotly-streamtoken': tk + } } - } - actual_streaming_specs = my_stream.get_streaming_specs() - eq_(expected_streaming_specs, actual_streaming_specs) + actual_streaming_specs = my_stream.get_streaming_specs() + self.assertEqual(expected_streaming_specs, actual_streaming_specs) From 0990b1d164fd6900039ed84ef246a89bfeeb07d1 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Tue, 17 May 2016 01:55:16 -0400 Subject: [PATCH 21/22] space fix --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 7efa2a1502d..3c146d51ecc 100644 --- a/circle.yml +++ b/circle.yml @@ -14,7 +14,7 @@ dependencies: # run all the pre-written installers (this will take a *while*) - bash circle/setup.sh - + # install testing tools for circle's version of things - pip install nose coverage - pip install -I . From 811b5d7719e57e59e22a9830c1fd115335077910 Mon Sep 17 00:00:00 2001 From: BRONSOLO Date: Tue, 17 May 2016 01:55:34 -0400 Subject: [PATCH 22/22] update version + fix changeling --- CHANGELOG.md | 5 ++--- plotly/version.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5d83b85745..1388cca8197 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] -## [1.10.0] - 2016-05-16 +## [1.9.12] - 2016-05-16 ### Added -SSL support for streaming. Requires the SSL module, which was backported in -Python v2.7.9, via chunked_requests submodule. +SSL support for streaming. ## [1.9.11] - 2016-05-02 ### Added diff --git a/plotly/version.py b/plotly/version.py index eed855dc752..b8f569b218e 100644 --- a/plotly/version.py +++ b/plotly/version.py @@ -1,2 +1,2 @@ -__version__ = '1.10.0' +__version__ = '1.9.12'