diff --git a/.circleci/config.yml b/.circleci/config.yml index c80a69b5129..34ffbca9d64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,68 +15,57 @@ jobs: command: "black --check ." # Core - python-2.7-core: + python-3.6-core: docker: - - image: circleci/python:2.7-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_27: python2.7 + - image: circleci/python:3.6-stretch-node-browsers steps: - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_36_core.txt" - run: - name: Test with tox - command: "cd packages/python/plotly; tox -e py27-core" + name: Test core + command: "cd packages/python/plotly; pytest plotly/tests/test_core" no_output_timeout: 20m - python-3.5-core: + python-3.7-core: docker: - - image: circleci/python:3.5-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_35: python3.5 - + - image: circleci/python:3.7-stretch-node-browsers steps: - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_37_core.txt" - run: - name: Test with tox - command: "cd packages/python/plotly; tox -e py35-core" + name: Test core + command: "cd packages/python/plotly; pytest plotly/tests/test_core" no_output_timeout: 20m - python-3.6-core: + python-3.8-core: docker: - - image: circleci/python:3.6-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_36: python3.6 - + - image: circleci/python:3.8-buster-node-browsers steps: - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_38_core.txt" - run: - name: Test with tox - command: "cd packages/python/plotly; tox -e py36-core" + name: Test core + command: "cd packages/python/plotly; pytest plotly/tests/test_core" no_output_timeout: 20m - python-3.7-core: + python-3.9-core: docker: - - image: circleci/python:3.7-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_37: python3.7 - + - image: circleci/python:3.9-buster-node-browsers steps: - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_39_core.txt" - run: - name: Test with tox - command: "cd packages/python/plotly; tox -e py37-core" + name: Test core + command: "cd packages/python/plotly; pytest plotly/tests/test_core" no_output_timeout: 20m python-3.7-percy: @@ -112,178 +101,130 @@ jobs: rm test/percy/*.html # Optional - python-2.7-optional: + python-3.6-optional: docker: - - image: circleci/python:2.7-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_27: python2.7 + - image: circleci/python:3.6-stretch-node-browsers steps: - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_36_optional.txt" - run: - name: Test with tox - command: "cd packages/python/plotly; tox -e py27-optional" + name: Test core + command: "cd packages/python/plotly; pytest plotly/tests/test_core" no_output_timeout: 20m - - python-3.5-optional: - docker: - - image: circleci/python:3.5-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_35: python3.5 - - steps: - - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Test optional + command: "cd packages/python/plotly; pytest plotly/tests/test_optional" + no_output_timeout: 40m - run: - name: Test with tox - command: "cd packages/python/plotly; tox -e py35-optional" + name: Test utils + command: "cd packages/python/plotly; pytest _plotly_utils/tests/" no_output_timeout: 20m - - python-3.6-optional: - docker: - - image: circleci/python:3.6-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_36: python3.6 - - steps: - - checkout - run: - name: Install tox - command: "sudo pip install tox" - - run: - name: Test with tox - command: "cd packages/python/plotly; tox -e py36-optional" + name: Test io + command: "cd packages/python/plotly; pytest plotly/tests/test_io" no_output_timeout: 20m python-3.7-optional: docker: - image: circleci/python:3.7-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_37: python3.7 steps: - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_37_optional.txt" - run: - name: Test with tox - command: "cd packages/python/plotly; tox -e py37-optional" + name: Test core + command: "cd packages/python/plotly; pytest plotly/tests/test_core" no_output_timeout: 20m - - # Plot.ly - python-2.7-plot_ly: - docker: - - image: circleci/python:2.7-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_27: python2.7 - - steps: - - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Test optional + command: "cd packages/python/plotly; pytest plotly/tests/test_optional" + no_output_timeout: 40m + - run: + name: Test utils + command: "cd packages/python/plotly; pytest _plotly_utils/tests/" + no_output_timeout: 20m - run: - name: Test with tox - command: "cd packages/python/chart-studio; tox -e py27-plot_ly" + name: Test io + command: "cd packages/python/plotly; pytest plotly/tests/test_io" no_output_timeout: 20m + - run: + name: Test dependencdies not imported + command: "cd packages/python/plotly; pytest -x test_init/test_dependencies_not_imported.py" + - run: + name: Test lazy imports + command: "cd packages/python/plotly; pytest -x test_init/test_lazy_imports.py" - python-3.5-plot_ly: + python-3.8-optional: docker: - - image: circleci/python:3.5-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_35: python3.5 + - image: circleci/python:3.8-buster-node-browsers steps: - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_38_optional.txt" - run: - name: Test with tox - command: "cd packages/python/chart-studio; tox -e py35-plot_ly" + name: Test core + command: "cd packages/python/plotly; pytest plotly/tests/test_core" no_output_timeout: 20m - - python-3.7-plot_ly: - docker: - - image: circleci/python:3.7-stretch-node-browsers - environment: - PLOTLY_TOX_PYTHON_37: python3.7 - - steps: - - checkout - run: - name: Install tox - command: "sudo pip install tox" + name: Test optional + command: "cd packages/python/plotly; pytest plotly/tests/test_optional" + no_output_timeout: 40m + - run: + name: Test utils + command: "cd packages/python/plotly; pytest _plotly_utils/tests/" + no_output_timeout: 20m - run: - name: Test with tox - command: "cd packages/python/chart-studio; tox -e py37-plot_ly" + name: Test io + command: "cd packages/python/plotly; pytest plotly/tests/test_io" no_output_timeout: 20m - python-2-7-orca: + python-3.9-optional: docker: - - image: circleci/node:10.9-stretch-browsers - environment: - PYTHON_VERSION: 2.7 + - image: circleci/python:3.9-buster-node-browsers steps: - checkout - - restore_cache: - keys: - - conda-27-v1-{{ checksum ".circleci/create_conda_optional_env.sh" }} - run: - name: Create conda environment - command: .circleci/create_conda_optional_env.sh - - - save_cache: - key: conda-27-v1-{{ checksum ".circleci/create_conda_optional_env.sh" }} - paths: - - /home/circleci/miniconda/ + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_39_optional.txt" - run: - name: Run Tests - command: | - . /home/circleci/miniconda/etc/profile.d/conda.sh - conda activate circle_optional - pytest --disable-warnings packages/python/plotly/plotly/tests/test_core - pytest packages/python/plotly/plotly/tests/test_orca - - - store_artifacts: - path: plotly/tests/test_orca/images/linux/failed + name: Test core + command: "cd packages/python/plotly; pytest plotly/tests/test_core" + no_output_timeout: 20m + - run: + name: Test optional + command: "cd packages/python/plotly; pytest plotly/tests/test_optional" + no_output_timeout: 40m + - run: + name: Test utils + command: "cd packages/python/plotly; pytest _plotly_utils/tests/" + no_output_timeout: 20m + - run: + name: Test io + command: "cd packages/python/plotly; pytest plotly/tests/test_io" + no_output_timeout: 20m - python-3-5-orca: + # Chart studio + python-3.7-chart_studio: docker: - - image: circleci/node:10.9-stretch-browsers - environment: - PYTHON_VERSION: 3.5 + - image: circleci/python:3.7-stretch-node-browsers steps: - checkout - - restore_cache: - keys: - - conda-35-v1-{{ checksum ".circleci/create_conda_optional_env.sh" }} - run: - name: Create conda environment - command: .circleci/create_conda_optional_env.sh - - - save_cache: - key: conda-35-v1-{{ checksum ".circleci/create_conda_optional_env.sh" }} - paths: - - /home/circleci/miniconda/ + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./chart-studio/test_requirements/requirements_37.txt" - run: - name: Run Tests - command: | - . /home/circleci/miniconda/etc/profile.d/conda.sh - conda activate circle_optional - pytest --disable-warnings packages/python/plotly/plotly/tests/test_core - pytest packages/python/plotly/plotly/tests/test_orca - - - store_artifacts: - path: plotly/tests/test_orca/images/linux/failed + name: Tests + command: "cd packages/python/chart-studio; pytest -x chart_studio/tests/" + no_output_timeout: 20m python-3-7-orca: docker: @@ -295,7 +236,7 @@ jobs: - checkout - restore_cache: keys: - - conda-37-v1-{{ checksum ".circleci/create_conda_optional_env.sh" }} + - conda-37-v1-{{ checksum ".circleci/create_conda_optional_env.sh" }}-{{ checksum "packages/python/plotly/test_requirements/requirements_37_optional.txt" }} - run: name: Create conda environment command: .circleci/create_conda_optional_env.sh @@ -320,14 +261,13 @@ jobs: docker: - image: circleci/python:3.7-stretch-node-browsers environment: - PLOTLY_TOX_PYTHON_37: python3.7 LANG: en_US.UTF-8 steps: - checkout - run: - name: Install tox - command: "sudo pip install tenacity tox black inflect" + name: Install dependencies + command: "cd packages/python; sudo pip install -r ./plotly/test_requirements/requirements_37_core.txt black inflect" - run: name: Update jupyterlab-plotly version command: "cd packages/python/plotly; python setup.py updateplotlywidgetversion" @@ -335,11 +275,8 @@ jobs: name: Update plotly.js to dev command: "cd packages/python/plotly; python setup.py updateplotlyjsdev" - run: - name: Test with tox - command: | - cd packages/python/plotly - locale - tox -e py37-core -- -k 'not nodev' + name: Test core + command: "cd packages/python/plotly; locale; pytest -k 'not nodev' plotly/tests/test_core" no_output_timeout: 20m - run: name: Commit @@ -517,16 +454,15 @@ workflows: build: jobs: - - python-2.7-core - - python-3.5-core - python-3.6-core - python-3.7-core + - python-3.8-core + - python-3.9-core - python-3.7-percy - - python-2.7-optional - - python-3.5-optional - python-3.6-optional - python-3.7-optional - - python-3.7-plot_ly - - python-2-7-orca + - python-3.8-optional + - python-3.9-optional + - python-3.7-chart_studio - python-3-7-orca - build-doc diff --git a/packages/python/chart-studio/test_requirements/requirements_37.txt b/packages/python/chart-studio/test_requirements/requirements_37.txt new file mode 100644 index 00000000000..b30b19ecb92 --- /dev/null +++ b/packages/python/chart-studio/test_requirements/requirements_37.txt @@ -0,0 +1,12 @@ +decorator==4.0.9 +nose==1.3.7 +requests==2.12.4 +six==1.10.0 +pytz==2016.10 +retrying==1.3.3 +pytest==3.5.1 +pandas==0.23.2 +numpy==1.14.3 +ipywidgets==7.2.0 +matplotlib==2.2.3 +--editable=./plotly diff --git a/packages/python/chart-studio/tox.ini b/packages/python/chart-studio/tox.ini deleted file mode 100644 index faddb36305f..00000000000 --- a/packages/python/chart-studio/tox.ini +++ /dev/null @@ -1,86 +0,0 @@ -; Tox is a testing tool that manages virtualenvs for testing multiple Python -; environments in a consistent/controlled way. - -; SETTING ENVIRONMENT VARIABLES AND TOX TESTING VARIABLES -; -; You can limit tox testing to certain environments via the `-e` (envlist) -; command line option: -; tox -e py27-core,py34-core -; OR, you can just set the `TOXENV` environment variable, which is handy: -; TOXENV=py27-core,py34-core -; -; Integrating with the virtualenvs in Circle CI is a bit of a pain. For -; whatever reason the "executable" `python35` (at the time of writing) cannot -; be activated directly. Instead the circle.yml file specifies the actual -; binary directly. Because of this, you too have to set the following env -; variables: -; PLOTLY_TOX_PYTHON_27=python2.7 -; PLOTLY_TOX_PYTHON_34=python3.4 -; ... -; These will be specific to your machine and may not look like the ones above. -; If you're not testing with all the python versions (see TOXENV above), -; there's no need to install and map other versions. - -; PASSING ADDITONAL ARGUMENTS TO TEST COMMANDS -; The {posargs} is tox-specific and passes in any command line args after `--`. -; For example, given the testing command in *this* file: -; pytest {posargs} -x plotly/tests/test_core -; -; The following command: -; tox -- -k 'not nodev' -; -; Tells tox to call: -; pytest -k 'not nodev' -x plotly/tests/test_core -; - -[tox] -; The py{A,B,C}-{X,Y} generates a matrix of envs: -; pyA-X,pyA-Y,pyB-X,pyB-Y,pyC-X,pyC-Y -envlist = py{27,34,37}-plot_ly - -; Note that envs can be targeted by deps using the : dep syntax. -; Only one dep is allowed per line as of the time of writing. The -; can be a `-` (hyphen) concatenated string of the environments to target -; with the given dep. - -; These commands are general and will be run for *all* environments. -[testenv] -passenv=PLOTLY_TOX_* -whitelist_externals= - mkdir -deps= - coverage==4.3.1 - decorator==4.0.9 - mock==2.0.0 - nose==1.3.7 - requests==2.12.4 - six==1.10.0 - pytz==2016.10 - retrying==1.3.3 - pytest==3.5.1 - backports.tempfile==1.0 - pandas==0.23.2 - numpy==1.14.3 - ipywidgets==7.2.0 - matplotlib==2.2.3 - --editable=file:///{toxinidir}/../plotly - - -; Plot.ly environments -[testenv:py27-plot_ly] -basepython={env:PLOTLY_TOX_PYTHON_27:} -commands= - python --version - pytest {posargs} -x chart_studio/tests/ - -[testenv:py35-plot_ly] -basepython={env:PLOTLY_TOX_PYTHON_35:} -commands= - python --version - pytest {posargs} -x chart_studio/tests/ - -[testenv:py37-plot_ly] -basepython={env:PLOTLY_TOX_PYTHON_37:} -commands= - python --version - pytest {posargs} -x chart_studio/tests/ diff --git a/packages/python/plotly/_plotly_utils/optional_imports.py b/packages/python/plotly/_plotly_utils/optional_imports.py index e76eab95f1c..33bd2d05f57 100644 --- a/packages/python/plotly/_plotly_utils/optional_imports.py +++ b/packages/python/plotly/_plotly_utils/optional_imports.py @@ -32,5 +32,5 @@ def get_module(name, should_load=True): _not_importable.add(name) except Exception as e: _not_importable.add(name) - msg = "Error importing optional module {}".format(name) + msg = f"Error importing optional module {name}" logger.exception(msg) diff --git a/packages/python/plotly/plotly/tests/test_core/test_figure_messages/test_add_traces.py b/packages/python/plotly/plotly/tests/test_core/test_figure_messages/test_add_traces.py index 63f379bbcd8..77054fcc9de 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_figure_messages/test_add_traces.py +++ b/packages/python/plotly/plotly/tests/test_core/test_figure_messages/test_add_traces.py @@ -66,36 +66,6 @@ def test_add_traces(self): ) -class TestAddTracesRowsColsDataTypes(TestCase): - def test_add_traces_with_iterable(self): - import plotly.express as px - - df = px.data.tips() - fig = px.scatter(df, x="total_bill", y="tip", color="day") - from plotly.subplots import make_subplots - - fig2 = make_subplots(1, 2) - fig2.add_traces(fig.data, rows=[1,] * len(fig.data), cols=[1,] * len(fig.data)) - - expected_data_length = 4 - - self.assertEqual(expected_data_length, len(fig2.data)) - - def test_add_traces_with_integers(self): - import plotly.express as px - - df = px.data.tips() - fig = px.scatter(df, x="total_bill", y="tip", color="day") - from plotly.subplots import make_subplots - - fig2 = make_subplots(1, 2) - fig2.add_traces(fig.data, rows=1, cols=2) - - expected_data_length = 4 - - self.assertEqual(expected_data_length, len(fig2.data)) - - def test_add_trace_exclude_empty_subplots(): # Add traces fig = make_subplots(2, 2) diff --git a/packages/python/plotly/plotly/tests/test_core/test_utils/test_utils.py b/packages/python/plotly/plotly/tests/test_core/test_utils/test_utils.py index 6122f27e7ee..0aff7eb2817 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_utils/test_utils.py +++ b/packages/python/plotly/plotly/tests/test_core/test_utils/test_utils.py @@ -2,12 +2,8 @@ from unittest import TestCase -import json as _json - from plotly.utils import PlotlyJSONEncoder, get_by_path, node_generator -from time import time -import numpy as np -import plotly.graph_objects as go +import json as _json class TestJSONEncoder(TestCase): @@ -21,38 +17,6 @@ def test_invalid_encode_exception(self): with self.assertRaises(TypeError): _json.dumps({"a": {1}}, cls=PlotlyJSONEncoder) - def test_fast_track_finite_arrays(self): - # if NaN or Infinity is found in the json dump - # of a figure, it is decoded and re-encoded to replace these values - # with null. This test checks that NaN and Infinity values are - # indeed converted to null, and that the encoding of figures - # without inf or nan is faster (because we can avoid decoding - # and reencoding). - z = np.random.randn(100, 100) - x = np.arange(100.0) - fig_1 = go.Figure(go.Heatmap(z=z, x=x)) - t1 = time() - json_str_1 = _json.dumps(fig_1, cls=PlotlyJSONEncoder) - t2 = time() - x[0] = np.nan - x[1] = np.inf - fig_2 = go.Figure(go.Heatmap(z=z, x=x)) - t3 = time() - json_str_2 = _json.dumps(fig_2, cls=PlotlyJSONEncoder) - t4 = time() - assert t2 - t1 < t4 - t3 - assert "null" in json_str_2 - assert "NaN" not in json_str_2 - assert "Infinity" not in json_str_2 - x = np.arange(100.0) - fig_3 = go.Figure(go.Heatmap(z=z, x=x)) - fig_3.update_layout(title_text="Infinity") - t5 = time() - json_str_3 = _json.dumps(fig_3, cls=PlotlyJSONEncoder) - t6 = time() - assert t2 - t1 < t6 - t5 - assert "Infinity" in json_str_3 - class TestGetByPath(TestCase): def test_get_by_path(self): @@ -86,46 +50,3 @@ def test_node_generator(self): ] for i, item in enumerate(node_generator(node0)): self.assertEqual(item, expected_node_path_tuples[i]) - - -class TestNumpyIntegerBaseType(TestCase): - def test_numpy_integer_import(self): - # should generate a figure with subplots of array and not throw a ValueError - import numpy as np - import plotly.graph_objects as go - from plotly.subplots import make_subplots - - indices_rows = np.array([1], dtype=np.int) - indices_cols = np.array([1], dtype=np.int) - fig = make_subplots(rows=1, cols=1) - fig.add_trace(go.Scatter(y=[1]), row=indices_rows[0], col=indices_cols[0]) - - data_path = ("data", 0, "y") - value = get_by_path(fig, data_path) - expected_value = (1,) - self.assertEqual(value, expected_value) - - def test_get_numpy_int_type(self): - import numpy as np - from _plotly_utils.utils import _get_int_type - - int_type_tuple = _get_int_type() - expected_tuple = (int, np.integer) - - self.assertEqual(int_type_tuple, expected_tuple) - - -class TestNoNumpyIntegerBaseType(TestCase): - def test_no_numpy_int_type(self): - import sys - from _plotly_utils.utils import _get_int_type - from _plotly_utils.optional_imports import get_module - - np = get_module("numpy", should_load=False) - if np: - sys.modules.pop("numpy") - - int_type_tuple = _get_int_type() - expected_tuple = (int,) - - self.assertEqual(int_type_tuple, expected_tuple) diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/__init__.py b/packages/python/plotly/plotly/tests/test_optional/test_autoshapes/__init__.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/__init__.py rename to packages/python/plotly/plotly/tests/test_optional/test_autoshapes/__init__.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_autoshapes/common.py b/packages/python/plotly/plotly/tests/test_optional/test_autoshapes/common.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_autoshapes/common.py rename to packages/python/plotly/plotly/tests/test_optional/test_autoshapes/common.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_autoshapes/test_annotated_shapes.py b/packages/python/plotly/plotly/tests/test_optional/test_autoshapes/test_annotated_shapes.py similarity index 99% rename from packages/python/plotly/plotly/tests/test_core/test_autoshapes/test_annotated_shapes.py rename to packages/python/plotly/plotly/tests/test_optional/test_autoshapes/test_annotated_shapes.py index 9c29282c942..8d7c3806991 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_autoshapes/test_annotated_shapes.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_autoshapes/test_annotated_shapes.py @@ -28,7 +28,7 @@ import sys import pytest import json -from common import _cmp_partial_dict, _check_figure_layout_objects +from .common import _cmp_partial_dict, _check_figure_layout_objects @pytest.fixture diff --git a/packages/python/plotly/plotly/tests/test_core/test_autoshapes/test_annotated_shapes_annotations.json b/packages/python/plotly/plotly/tests/test_optional/test_autoshapes/test_annotated_shapes_annotations.json similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_autoshapes/test_annotated_shapes_annotations.json rename to packages/python/plotly/plotly/tests/test_optional/test_autoshapes/test_annotated_shapes_annotations.json diff --git a/packages/python/plotly/plotly/tests/test_core/test_autoshapes/test_axis_span_shapes.py b/packages/python/plotly/plotly/tests/test_optional/test_autoshapes/test_axis_span_shapes.py similarity index 99% rename from packages/python/plotly/plotly/tests/test_core/test_autoshapes/test_axis_span_shapes.py rename to packages/python/plotly/plotly/tests/test_optional/test_autoshapes/test_axis_span_shapes.py index 4fef85fe338..12d36cf3c04 100644 --- a/packages/python/plotly/plotly/tests/test_core/test_autoshapes/test_axis_span_shapes.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_autoshapes/test_axis_span_shapes.py @@ -3,7 +3,7 @@ from plotly.basedatatypes import _indexing_combinations import plotly.express as px import pytest -from common import _cmp_partial_dict, _check_figure_layout_objects +from .common import _cmp_partial_dict, _check_figure_layout_objects @pytest.fixture diff --git a/packages/python/plotly/plotly/tests/test_optional/test_offline/test_offline.py b/packages/python/plotly/plotly/tests/test_optional/test_offline/test_offline.py index d36934d1eae..a50fa4e7675 100644 --- a/packages/python/plotly/plotly/tests/test_optional/test_offline/test_offline.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_offline/test_offline.py @@ -40,6 +40,7 @@ def test_iplot_works_after_you_call_init_notebook_mode(self): @pytest.mark.matplotlib def test_iplot_mpl_works(self): + plotly.offline.init_notebook_mode() # Generate matplotlib plot for tests fig = plt.figure() diff --git a/packages/python/plotly/plotly/tests/test_optional/test_px/__init__.py b/packages/python/plotly/plotly/tests/test_optional/test_px/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_colors.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_colors.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_colors.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_colors.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_facets.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_facets.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_facets.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_facets.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_imshow.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_imshow.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_imshow.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_imshow.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_marginals.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_marginals.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_marginals.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_marginals.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_pandas_backend.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_pandas_backend.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_pandas_backend.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_pandas_backend.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_px.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_px.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_px.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px_functions.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_px_functions.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_px_functions.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_hover.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px_hover.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_px_hover.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_px_hover.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_input.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px_input.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_px_input.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_px_input.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_px_wide.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_px_wide.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_px_wide.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_px_wide.py diff --git a/packages/python/plotly/plotly/tests/test_core/test_px/test_trendline.py b/packages/python/plotly/plotly/tests/test_optional/test_px/test_trendline.py similarity index 100% rename from packages/python/plotly/plotly/tests/test_core/test_px/test_trendline.py rename to packages/python/plotly/plotly/tests/test_optional/test_px/test_trendline.py diff --git a/packages/python/plotly/plotly/tests/test_optional/test_subplots/test_make_subplots.py b/packages/python/plotly/plotly/tests/test_optional/test_subplots/test_make_subplots.py index 0edcacebd1e..09555497ac3 100644 --- a/packages/python/plotly/plotly/tests/test_optional/test_subplots/test_make_subplots.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_subplots/test_make_subplots.py @@ -16,3 +16,33 @@ def test_subplot_titles_numpy_array(self): subplot_titles=np.array(["", "Inset"]), ) self.assertEqual(fig, expected) + + +class TestAddTracesRowsColsDataTypes(TestCase): + def test_add_traces_with_iterable(self): + import plotly.express as px + + df = px.data.tips() + fig = px.scatter(df, x="total_bill", y="tip", color="day") + from plotly.subplots import make_subplots + + fig2 = make_subplots(1, 2) + fig2.add_traces(fig.data, rows=[1,] * len(fig.data), cols=[1,] * len(fig.data)) + + expected_data_length = 4 + + self.assertEqual(expected_data_length, len(fig2.data)) + + def test_add_traces_with_integers(self): + import plotly.express as px + + df = px.data.tips() + fig = px.scatter(df, x="total_bill", y="tip", color="day") + from plotly.subplots import make_subplots + + fig2 = make_subplots(1, 2) + fig2.add_traces(fig.data, rows=1, cols=2) + + expected_data_length = 4 + + self.assertEqual(expected_data_length, len(fig2.data)) diff --git a/packages/python/plotly/plotly/tests/test_optional/test_utils/test_utils.py b/packages/python/plotly/plotly/tests/test_optional/test_utils/test_utils.py index 79ce6a7f320..3145c0cb139 100644 --- a/packages/python/plotly/plotly/tests/test_optional/test_utils/test_utils.py +++ b/packages/python/plotly/plotly/tests/test_optional/test_utils/test_utils.py @@ -9,6 +9,7 @@ import decimal from datetime import datetime as dt from unittest import TestCase +from time import time import pytest import numpy as np @@ -20,7 +21,9 @@ import base64 from plotly import optional_imports, utils +import plotly.graph_objects as go from plotly.graph_objs import Scatter, Scatter3d, Figure, Data +from plotly.utils import get_by_path from PIL import Image @@ -358,11 +361,101 @@ def test_pil_image_encoding(self): j1 = _json.dumps({"source": img}, cls=utils.PlotlyJSONEncoder) assert j1 == '{"source": "%s"}' % expected_uri + def test_nan_to_null(self): + array = [1, float("NaN"), float("Inf"), float("-Inf"), "platypus"] + result = _json.dumps(array, cls=utils.PlotlyJSONEncoder) + expected_result = '[1, null, null, null, "platypus"]' + self.assertEqual(result, expected_result) + + def test_invalid_encode_exception(self): + with self.assertRaises(TypeError): + _json.dumps({"a": {1}}, cls=utils.PlotlyJSONEncoder) + + def test_fast_track_finite_arrays(self): + # if NaN or Infinity is found in the json dump + # of a figure, it is decoded and re-encoded to replace these values + # with null. This test checks that NaN and Infinity values are + # indeed converted to null, and that the encoding of figures + # without inf or nan is faster (because we can avoid decoding + # and reencoding). + z = np.random.randn(100, 100) + x = np.arange(100.0) + fig_1 = go.Figure(go.Heatmap(z=z, x=x)) + t1 = time() + json_str_1 = _json.dumps(fig_1, cls=utils.PlotlyJSONEncoder) + t2 = time() + x[0] = np.nan + x[1] = np.inf + fig_2 = go.Figure(go.Heatmap(z=z, x=x)) + t3 = time() + json_str_2 = _json.dumps(fig_2, cls=utils.PlotlyJSONEncoder) + t4 = time() + assert t2 - t1 < t4 - t3 + assert "null" in json_str_2 + assert "NaN" not in json_str_2 + assert "Infinity" not in json_str_2 + x = np.arange(100.0) + fig_3 = go.Figure(go.Heatmap(z=z, x=x)) + fig_3.update_layout(title_text="Infinity") + t5 = time() + json_str_3 = _json.dumps(fig_3, cls=utils.PlotlyJSONEncoder) + t6 = time() + assert t2 - t1 < t6 - t5 + assert "Infinity" in json_str_3 + + +class TestNumpyIntegerBaseType(TestCase): + def test_numpy_integer_import(self): + # should generate a figure with subplots of array and not throw a ValueError + import numpy as np + import plotly.graph_objects as go + from plotly.subplots import make_subplots + + indices_rows = np.array([1], dtype=np.int) + indices_cols = np.array([1], dtype=np.int) + fig = make_subplots(rows=1, cols=1) + fig.add_trace(go.Scatter(y=[1]), row=indices_rows[0], col=indices_cols[0]) + + data_path = ("data", 0, "y") + value = get_by_path(fig, data_path) + expected_value = (1,) + self.assertEqual(value, expected_value) + + def test_get_numpy_int_type(self): + import numpy as np + from _plotly_utils.utils import _get_int_type + + int_type_tuple = _get_int_type() + expected_tuple = (int, np.integer) + + self.assertEqual(int_type_tuple, expected_tuple) + + +class TestNoNumpyIntegerBaseType(TestCase): + def test_no_numpy_int_type(self): + import sys + from _plotly_utils.utils import _get_int_type + from _plotly_utils.optional_imports import get_module + + np = get_module("numpy", should_load=False) + if np: + sys.modules.pop("numpy") + + int_type_tuple = _get_int_type() + expected_tuple = (int,) + + self.assertEqual(int_type_tuple, expected_tuple) + if matplotlylib: @pytest.mark.matplotlib def test_masked_constants_example(): + try: + pd.options.plotting.backend = "matplotlib" + except Exception: + pass + # example from: https://gist.github.com/tschaume/d123d56bf586276adb98 data = { "esN": [0, 1, 2, 3], diff --git a/packages/python/plotly/setup.py b/packages/python/plotly/setup.py index 172eb25d8df..093010f5dff 100644 --- a/packages/python/plotly/setup.py +++ b/packages/python/plotly/setup.py @@ -457,16 +457,13 @@ def run(self): long_description_content_type="text/markdown", classifiers=[ "Development Status :: 5 - Production/Stable", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", "Topic :: Scientific/Engineering :: Visualization", ], + python_requires=">=3.6", license="MIT", packages=[ "plotly", diff --git a/packages/python/plotly/test_requirements/requirements_36_core.txt b/packages/python/plotly/test_requirements/requirements_36_core.txt new file mode 100644 index 00000000000..6265e5b540e --- /dev/null +++ b/packages/python/plotly/test_requirements/requirements_36_core.txt @@ -0,0 +1,4 @@ +requests==2.12.4 +six==1.10.0 +tenacity==6.2.0 +pytest==3.5.1 diff --git a/packages/python/plotly/test_requirements/requirements_36_optional.txt b/packages/python/plotly/test_requirements/requirements_36_optional.txt new file mode 100644 index 00000000000..f86591ca21c --- /dev/null +++ b/packages/python/plotly/test_requirements/requirements_36_optional.txt @@ -0,0 +1,24 @@ +requests==2.12.4 +six==1.10.0 +tenacity==6.2.0 +pandas==0.24.2 +numpy==1.19.5 +xarray==0.10.9 +statsmodels==0.10.2 +pillow==5.2.0 +pytest==3.5.1 +pytz==2016.10 + +--editable=./plotly-geo +ipython[all]==5.1.0 +ipywidgets==7.2.0 +ipykernel==4.8.2 +jupyter==1.0.0 +scipy==1.2.3 +shapely==1.7.0 +geopandas==0.3.0 +pyshp==1.2.10 +matplotlib==2.2.3 +scikit-image==0.14.4 +psutil==5.7.0 +kaleido diff --git a/packages/python/plotly/test_requirements/requirements_37_core.txt b/packages/python/plotly/test_requirements/requirements_37_core.txt new file mode 100644 index 00000000000..6265e5b540e --- /dev/null +++ b/packages/python/plotly/test_requirements/requirements_37_core.txt @@ -0,0 +1,4 @@ +requests==2.12.4 +six==1.10.0 +tenacity==6.2.0 +pytest==3.5.1 diff --git a/packages/python/plotly/test_requirements/requirements_37_optional.txt b/packages/python/plotly/test_requirements/requirements_37_optional.txt new file mode 100644 index 00000000000..f86591ca21c --- /dev/null +++ b/packages/python/plotly/test_requirements/requirements_37_optional.txt @@ -0,0 +1,24 @@ +requests==2.12.4 +six==1.10.0 +tenacity==6.2.0 +pandas==0.24.2 +numpy==1.19.5 +xarray==0.10.9 +statsmodels==0.10.2 +pillow==5.2.0 +pytest==3.5.1 +pytz==2016.10 + +--editable=./plotly-geo +ipython[all]==5.1.0 +ipywidgets==7.2.0 +ipykernel==4.8.2 +jupyter==1.0.0 +scipy==1.2.3 +shapely==1.7.0 +geopandas==0.3.0 +pyshp==1.2.10 +matplotlib==2.2.3 +scikit-image==0.14.4 +psutil==5.7.0 +kaleido diff --git a/packages/python/plotly/test_requirements/requirements_38_core.txt b/packages/python/plotly/test_requirements/requirements_38_core.txt new file mode 100644 index 00000000000..7f8c791a85e --- /dev/null +++ b/packages/python/plotly/test_requirements/requirements_38_core.txt @@ -0,0 +1,4 @@ +requests==2.25.1 +six==1.15.0 +tenacity==6.2.0 +pytest==6.2.3 diff --git a/packages/python/plotly/test_requirements/requirements_38_optional.txt b/packages/python/plotly/test_requirements/requirements_38_optional.txt new file mode 100644 index 00000000000..091c415b25b --- /dev/null +++ b/packages/python/plotly/test_requirements/requirements_38_optional.txt @@ -0,0 +1,24 @@ +requests==2.25.1 +six==1.15.0 +tenacity==6.2.0 +pandas==1.2.4 +numpy==1.20.2 +xarray==0.17.0 +statsmodels +Pillow==8.2.0 +pytest==6.2.3 +pytz==2021.1 + +--editable=./plotly-geo +ipython[all]==7.22.0 +ipywidgets==7.6.3 +ipykernel==5.5.3 +jupyter==1.0.0 +scipy==1.6.2 +Shapely==1.7.1 +geopandas==0.9.0 +pyshp==2.1.3 +matplotlib==2.2.3 +scikit-image==0.18.1 +psutil==5.7.0 +kaleido diff --git a/packages/python/plotly/test_requirements/requirements_39_core.txt b/packages/python/plotly/test_requirements/requirements_39_core.txt new file mode 100644 index 00000000000..7f8c791a85e --- /dev/null +++ b/packages/python/plotly/test_requirements/requirements_39_core.txt @@ -0,0 +1,4 @@ +requests==2.25.1 +six==1.15.0 +tenacity==6.2.0 +pytest==6.2.3 diff --git a/packages/python/plotly/test_requirements/requirements_39_optional.txt b/packages/python/plotly/test_requirements/requirements_39_optional.txt new file mode 100644 index 00000000000..091c415b25b --- /dev/null +++ b/packages/python/plotly/test_requirements/requirements_39_optional.txt @@ -0,0 +1,24 @@ +requests==2.25.1 +six==1.15.0 +tenacity==6.2.0 +pandas==1.2.4 +numpy==1.20.2 +xarray==0.17.0 +statsmodels +Pillow==8.2.0 +pytest==6.2.3 +pytz==2021.1 + +--editable=./plotly-geo +ipython[all]==7.22.0 +ipywidgets==7.6.3 +ipykernel==5.5.3 +jupyter==1.0.0 +scipy==1.6.2 +Shapely==1.7.1 +geopandas==0.9.0 +pyshp==2.1.3 +matplotlib==2.2.3 +scikit-image==0.18.1 +psutil==5.7.0 +kaleido diff --git a/packages/python/plotly/tox.ini b/packages/python/plotly/tox.ini deleted file mode 100644 index d4e6254866d..00000000000 --- a/packages/python/plotly/tox.ini +++ /dev/null @@ -1,151 +0,0 @@ -; Tox is a testing tool that manages virtualenvs for testing multiple Python -; environments in a consistent/controlled way. - -; SETTING ENVIRONMENT VARIABLES AND TOX TESTING VARIABLES -; -; You can limit tox testing to certain environments via the `-e` (envlist) -; command line option: -; tox -e py27-core,py34-core -; OR, you can just set the `TOXENV` environment variable, which is handy: -; TOXENV=py27-core,py34-core -; -; Integrating with the virtualenvs in Circle CI is a bit of a pain. For -; whatever reason the "executable" `python35` (at the time of writing) cannot -; be activated directly. Instead the circle.yml file specifies the actual -; binary directly. Because of this, you too have to set the following env -; variables: -; PLOTLY_TOX_PYTHON_27=python2.7 -; PLOTLY_TOX_PYTHON_34=python3.4 -; ... -; These will be specific to your machine and may not look like the ones above. -; If you're not testing with all the python versions (see TOXENV above), -; there's no need to install and map other versions. - -; PASSING ADDITONAL ARGUMENTS TO TEST COMMANDS -; The {posargs} is tox-specific and passes in any command line args after `--`. -; For example, given the testing command in *this* file: -; pytest {posargs} plotly/tests/test_core -; -; The following command: -; tox -- -k 'not nodev' -; -; Tells tox to call: -; pytest -k 'not nodev' plotly/tests/test_core -; - -[tox] -; The py{A,B,C}-{X,Y} generates a matrix of envs: -; pyA-X,pyA-Y,pyB-X,pyB-Y,pyC-X,pyC-Y -envlist = py{27,34,35,36,37}-{core,optional},py{27,34,37} - -; Note that envs can be targeted by deps using the : dep syntax. -; Only one dep is allowed per line as of the time of writing. The -; can be a `-` (hyphen) concatenated string of the environments to target -; with the given dep. - -; These commands are general and will be run for *all* environments. -[testenv] -passenv=PLOTLY_TOX_* -whitelist_externals= - mkdir -deps= - coverage==4.3.1 - decorator==4.0.9 - mock==2.0.0 - requests==2.12.4 - six==1.10.0 - pytz==2016.10 - tenacity==6.2.0 - pytest==3.5.1 - pandas==0.24.2 - numpy==1.19.5 - xarray==0.10.9 - statsmodels==0.10.2 - pillow==5.2.0 - backports.tempfile==1.0 - optional: --editable=file:///{toxinidir}/../plotly-geo - optional: ipython[all]==5.1.0 - optional: ipywidgets==7.2.0 - optional: ipykernel==4.8.2 - optional: jupyter==1.0.0 - optional: scipy==1.2.3 - optional: shapely==1.7.0 - optional: geopandas==0.3.0 - optional: pyshp==1.2.10 - optional: matplotlib==2.2.3 - optional: scikit-image==0.14.4 - optional: kaleido - -; CORE ENVIRONMENTS -[testenv:py27-core] -basepython={env:PLOTLY_TOX_PYTHON_27:} -commands= - python --version - pytest {posargs} plotly/tests/test_core - -[testenv:py35-core] -basepython={env:PLOTLY_TOX_PYTHON_35:} -commands= - python --version - pytest {posargs} plotly/tests/test_core - -[testenv:py36-core] -basepython={env:PLOTLY_TOX_PYTHON_36:} -commands= - python --version - pytest {posargs} plotly/tests/test_core - -[testenv:py37-core] -basepython={env:PLOTLY_TOX_PYTHON_37:} -commands= - python --version - pytest {posargs} plotly/tests/test_core - pytest {posargs} -x test_init/test_dependencies_not_imported.py - pytest {posargs} -x test_init/test_lazy_imports.py - -; OPTIONAL ENVIRONMENTS -;[testenv:py27-optional] -;basepython={env:PLOTLY_TOX_PYTHON_27:} -;commands= -; python --version -;; Do some coverage reporting. No need to do this for all environments. -; mkdir -p {envbindir}/../../coverage-reports/{envname} -; coverage erase -; coverage run --include="*/plotly/*" --omit="*/tests*" {envbindir}/nosetests {posargs} plotly/tests -; coverage html -d "{envbindir}/../../coverage-reports/{envname}" --title={envname} - -[testenv:py27-optional] -basepython={env:PLOTLY_TOX_PYTHON_27:} -commands= - python --version - pytest {posargs} plotly/tests/test_core - pytest {posargs} plotly/tests/test_optional - pytest _plotly_utils/tests/ - pytest plotly/tests/test_io - -[testenv:py35-optional] -basepython={env:PLOTLY_TOX_PYTHON_35:} -commands= - python --version - pytest {posargs} plotly/tests/test_core - pytest {posargs} plotly/tests/test_optional - pytest _plotly_utils/tests/ - pytest plotly/tests/test_io - -[testenv:py36-optional] -basepython={env:PLOTLY_TOX_PYTHON_36:} -commands= - python --version - pytest {posargs} plotly/tests/test_core - pytest {posargs} plotly/tests/test_optional - pytest _plotly_utils/tests/ - pytest plotly/tests/test_io - -[testenv:py37-optional] -basepython={env:PLOTLY_TOX_PYTHON_37:} -commands= - python --version - pytest {posargs} plotly/tests/test_core - pytest {posargs} plotly/tests/test_optional - pytest _plotly_utils/tests/ - pytest plotly/tests/test_io