Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attempt to replace nose with pytest #2217

Merged
merged 10 commits into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ jobs:
command: |
cd packages/python/plotly
locale
tox -e py37-core -- -a '!nodev'
tox -e py37-core -- -k 'not nodev'
no_output_timeout: 20m
- run:
name: Commit
Expand Down
24 changes: 12 additions & 12 deletions contributing.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

The bottom line. Follow your Nose, or our Nose. Write-run-love tests :fist:.
Thank you for contributing to plotly.py!

## Code of Conduct

Expand Down Expand Up @@ -128,34 +128,34 @@ classes based on the new schema.
We take advantage of two tools to run tests:

* [`tox`](https://tox.readthedocs.io/en/latest/), which is both a virtualenv management and test tool.
* [`nose`](https://nose.readthedocs.org/en/latest/), which is is an extension of Python's unittest
* [`pytest`](https://docs.pytest.org/en/latest/), a powerful framework for unit testing.

### Running Tests with `nose`
### Running Tests with `pytest`

Since our tests cover *all* the functionality, to prevent tons of errors from showing up and having to parse through a messy output, you'll need to install `optional-requirements.txt` as explained above.

After you've done that, go ahead and follow (y)our Nose!
After you've done that, go ahead and run the test suite!

```bash
nosetests -w packages/python/plotly/plotly/tests/
pytest packages/python/plotly/plotly/tests/
```

Or for more *verbose* output:

```bash
nosetests -w packages/python/plotly/plotly/tests/ -v
pytest -v packages/python/plotly/plotly/tests/
```

Either of those will run *every* test we've written for the Python API. You can get more granular by running something like:

```bash
nosetests -w packages/python/plotly/plotly/tests/test_core/
pytest packages/python/plotly/plotly/tests/test_core/
```

... or even more granular by running something like:

```bash
nosetests plotly/tests/test_plotly/test_plot.py
pytest plotly/tests/test_plotly/test_plot.py
```
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh can we add here the incantation for running a single test? I think it’s with a colon? I always forget it!


### Running tests with `tox`
Expand Down Expand Up @@ -187,16 +187,16 @@ Where `TOXENV` is the environment list you want to use when invoking `tox` from
* `tox` will automatically manage a virtual env for each environment you want to test in.
* You only have to run `tox` and know that the module is working in both `Python 2` and `Python 3`.

Finally, `tox` allows you to pass in additional command line arguments that are formatted in (by us) in the `tox.ini` file, see `{posargs}`. This is setup to help with our `nose attr` configuration. To run only tests that are *not* tagged with `slow`, you could use the following command:
Finally, `tox` allows you to pass in additional command line arguments that are formatted in (by us) in the `tox.ini` file, see `{posargs}`. This is setup to help with our configuration of [pytest markers](http://doc.pytest.org/en/latest/example/markers.html), which are set up in `packages/python/plotly/pytest.ini`. To run only tests that are *not* tagged with `nodev`, you could use the following command:

```bash
tox -- -a '!slow'
tox -- -a '!nodev'
```

Note that anything after `--` is substituted in for `{posargs}` in the tox.ini. For completeness, because it's reasonably confusing, if you want to force a match for *multiple* `nose attr` tags, you comma-separate the tags like so:
Note that anything after `--` is substituted in for `{posargs}` in the tox.ini. For completeness, because it's reasonably confusing, if you want to force a match for *multiple* `pytest` marker tags, you comma-separate the tags like so:

```bash
tox -- -a '!slow','!matplotlib'
tox -- -a '!nodev','!matplotlib'
```

### Writing Tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from unittest import TestCase

from nose.tools import raises
import pytest

import chart_studio.tools as tls
from _plotly_utils.exceptions import PlotlyError
Expand All @@ -13,10 +13,10 @@ def test_get_valid_embed():
tls.get_embed(url)


@raises(PlotlyError)
def test_get_invalid_embed():
url = "https://plot.ly/~PlotBot/a/"
tls.get_embed(url)
with pytest.raises(PlotlyError):
tls.get_embed(url)


class TestGetEmbed(TestCase):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,38 @@
"""
from __future__ import absolute_import

from nose.plugins.attrib import attr
from nose.tools import raises

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


emmanuelle marked this conversation as resolved.
Show resolved Hide resolved
@attr("matplotlib")
@pytest.mark.matplotlib
class PlotMPLTest(TestCase):
def setUp(self):
py.sign_in("PlotlyImageTest", "786r5mecv0", plotly_domain="https://plot.ly")

@raises(_plotly_utils.exceptions.PlotlyGraphObjectError)
def test_update_type_error(self):
fig, ax = plt.subplots()
ax.plot([1, 2, 3])
update = []
py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
with pytest.raises(_plotly_utils.exceptions.PlotlyGraphObjectError):
py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)

@raises(KeyError)
def test_update_validation_error(self):
fig, ax = plt.subplots()
ax.plot([1, 2, 3])
update = {"invalid": "anything"}
py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
with pytest.raises(KeyError):
py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)

@attr("slow")
def test_update(self):
fig, ax = plt.subplots()
ax.plot([1, 2, 3])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@
import random
import string

from nose.plugins.attrib import attr

from chart_studio import plotly as py
from chart_studio.exceptions import PlotlyRequestError
from chart_studio.tests.utils import PlotlyTestCase


@attr("slow")
class FolderAPITestCase(PlotlyTestCase):
def setUp(self):
super(FolderAPITestCase, self).setUp()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from unittest import skipIf

import six
from nose.plugins.attrib import attr

import _plotly_utils.exceptions
from chart_studio import exceptions
Expand Down Expand Up @@ -38,15 +37,13 @@ def is_trivial(obj):


class GetFigureTest(PlotlyTestCase):
@attr("slow")
def test_get_figure(self):
un = "PlotlyImageTest"
ak = "786r5mecv0"
file_id = 13183
py.sign_in(un, ak)
py.get_figure("PlotlyImageTest", str(file_id))

@attr("slow")
def test_get_figure_with_url(self):
un = "PlotlyImageTest"
ak = "786r5mecv0"
Expand All @@ -62,7 +59,6 @@ def test_get_figure_invalid_1(self):
with self.assertRaises(exceptions.PlotlyError):
py.get_figure(url)

@attr("slow")
def test_get_figure_invalid_2(self):
un = "PlotlyImageTest"
ak = "786r5mecv0"
Expand All @@ -80,7 +76,6 @@ def test_get_figure_invalid_3(self):
with self.assertRaises(ValueError):
py.get_figure(url)

@attr("slow")
def test_get_figure_does_not_exist(self):
un = "PlotlyImageTest"
ak = "786r5mecv0"
Expand All @@ -89,7 +84,6 @@ def test_get_figure_does_not_exist(self):
with self.assertRaises(_plotly_utils.exceptions.PlotlyError):
py.get_figure(url)

@attr("slow")
def test_get_figure_raw(self):
un = "PlotlyImageTest"
ak = "786r5mecv0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import requests
import six
from nose.plugins.attrib import attr
import json as _json

from chart_studio.tests.utils import PlotlyTestCase
Expand All @@ -25,7 +24,6 @@


class GetRequestsTest(PlotlyTestCase):
@attr("slow")
def test_user_does_not_exist(self):
username = "user_does_not_exist"
api_key = "invalid-apikey"
Expand All @@ -47,7 +45,6 @@ def test_user_does_not_exist(self):
self.assertEqual(response.status_code, 404)
self.assertEqual(content["error"], error_message)

@attr("slow")
def test_file_does_not_exist(self):
username = "PlotlyImageTest"
api_key = "786r5mecv0"
Expand All @@ -68,7 +65,6 @@ def test_file_does_not_exist(self):
self.assertEqual(response.status_code, 404)
self.assertEqual(content["error"], error_message)

@attr("slow")
def test_wrong_api_key(self): # TODO: does this test the right thing?
username = "PlotlyImageTest"
api_key = "invalid-apikey"
Expand All @@ -85,7 +81,6 @@ def test_wrong_api_key(self): # TODO: does this test the right thing?
# Locked File
# TODO

@attr("slow")
def test_private_permission_defined(self):
username = "PlotlyImageTest"
api_key = "786r5mecv0"
Expand All @@ -105,7 +100,6 @@ def test_private_permission_defined(self):
# Private File that is shared
# TODO

@attr("slow")
def test_missing_headers(self):
file_owner = "get_test_user"
file_id = 0
Expand All @@ -121,7 +115,6 @@ def test_missing_headers(self):
content = _json.loads(response.content.decode("unicode_escape"))
self.assertEqual(response.status_code, 422)

@attr("slow")
def test_valid_request(self):
username = "PlotlyImageTest"
api_key = "786r5mecv0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import string
from unittest import skip

from nose.plugins.attrib import attr

from chart_studio import plotly as py
from chart_studio.exceptions import InputError, PlotlyRequestError
Expand Down Expand Up @@ -54,19 +53,16 @@ def upload_and_return_grid(self):
return g

# Nominal usage
@attr("slow")
def test_grid_upload(self):
self.upload_and_return_grid()

@attr("slow")
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)

@attr("slow")
def test_grid_upload_in_existing_folder(self):
g = self.get_grid()
folder = random_filename()
Expand All @@ -75,19 +71,16 @@ def test_grid_upload_in_existing_folder(self):
path = "existing folder: {0}/grid in folder {1}".format(folder, filename)
py.grid_ops.upload(g, path, auto_open=False)

@attr("slow")
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)

@attr("slow")
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)

@attr("slow")
def test_plot_from_grid(self):
g = self.upload_and_return_grid()
url = py.plot(
Expand All @@ -97,7 +90,6 @@ def test_plot_from_grid(self):
)
return url, g

@attr("slow")
def test_get_figure_from_references(self):
url, g = self.test_plot_from_grid()
fig = py.get_figure(url)
Expand Down Expand Up @@ -143,7 +135,6 @@ def test_row_append_of_non_uploaded_grid(self):
py.grid_ops.append_rows(rows, grid=g)

# Input Errors
@attr("slow")
def test_unequal_length_rows(self):
g = self.upload_and_return_grid()
rows = [[1, 2], ["to", "many", "cells"]]
Expand All @@ -158,7 +149,6 @@ def test_duplicate_columns(self):
Grid([c1, c2])

# Test delete
@attr("slow")
def test_delete_grid(self):
g = self.get_grid()
fn = random_filename()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@
import itertools
import warnings

from nose.plugins.attrib import attr

import _plotly_utils.exceptions
from chart_studio.plotly import plotly as py
from chart_studio.tests.utils import PlotlyTestCase


@attr("slow")
class TestImage(PlotlyTestCase):
def setUp(self):
super(TestImage, self).setUp()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import random
import string

from nose.plugins.attrib import attr
from unittest import skip

from chart_studio import plotly as py
Expand All @@ -33,15 +32,13 @@ def random_filename(self):
unique_filename = "Valid Grid with Meta " + "".join(random_chars)
return unique_filename

@attr("slow")
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)

@attr("slow")
def test_upload_meta_with_grid(self):
c1 = Column([1, 2, 3, 4], "first column")
Grid([c1])
Expand Down
Loading