Skip to content

Commit 1e289c4

Browse files
authored
Merge pull request #2217 from plotly/nose-to-pytest
attempt to replace nose with pytest
2 parents 2918c24 + 5963c98 commit 1e289c4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+240
-297
lines changed

Diff for: .circleci/config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ jobs:
339339
command: |
340340
cd packages/python/plotly
341341
locale
342-
tox -e py37-core -- -a '!nodev'
342+
tox -e py37-core -- -k 'not nodev'
343343
no_output_timeout: 20m
344344
- run:
345345
name: Commit

Diff for: contributing.md

+18-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Contributing
22

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

55
## Code of Conduct
66

@@ -128,34 +128,40 @@ classes based on the new schema.
128128
We take advantage of two tools to run tests:
129129

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

133-
### Running Tests with `nose`
133+
### Running Tests with `pytest`
134134

135135
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.
136136

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

139139
```bash
140-
nosetests -w packages/python/plotly/plotly/tests/
140+
pytest packages/python/plotly/plotly/tests/
141141
```
142142

143143
Or for more *verbose* output:
144144

145145
```bash
146-
nosetests -w packages/python/plotly/plotly/tests/ -v
146+
pytest -v packages/python/plotly/plotly/tests/
147147
```
148148

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

151151
```bash
152-
nosetests -w packages/python/plotly/plotly/tests/test_core/
152+
pytest packages/python/plotly/plotly/tests/test_core/
153153
```
154154

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

157157
```bash
158-
nosetests plotly/tests/test_plotly/test_plot.py
158+
pytest plotly/tests/test_plotly/test_plot.py
159+
```
160+
161+
or for a specfic test function
162+
163+
```bash
164+
pytest plotly/tests/test_plotly/test_plot.py::test_function
159165
```
160166

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

190-
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:
196+
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:
191197

192198
```bash
193-
tox -- -a '!slow'
199+
tox -- -a '!nodev'
194200
```
195201

196-
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:
202+
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:
197203

198204
```bash
199-
tox -- -a '!slow','!matplotlib'
205+
tox -- -a '!nodev','!matplotlib'
200206
```
201207

202208
### Writing Tests

Diff for: packages/python/chart-studio/chart_studio/tests/test_core/test_tools/test_get_embed.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from unittest import TestCase
44

5-
from nose.tools import raises
5+
import pytest
66

77
import chart_studio.tools as tls
88
from _plotly_utils.exceptions import PlotlyError
@@ -13,10 +13,10 @@ def test_get_valid_embed():
1313
tls.get_embed(url)
1414

1515

16-
@raises(PlotlyError)
1716
def test_get_invalid_embed():
1817
url = "https://plot.ly/~PlotBot/a/"
19-
tls.get_embed(url)
18+
with pytest.raises(PlotlyError):
19+
tls.get_embed(url)
2020

2121

2222
class TestGetEmbed(TestCase):

Diff for: packages/python/chart-studio/chart_studio/tests/test_optional/test_matplotlylib/test_plot_mpl.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -7,40 +7,38 @@
77
"""
88
from __future__ import absolute_import
99

10-
from nose.plugins.attrib import attr
11-
from nose.tools import raises
1210

1311
import _plotly_utils.exceptions
1412
from plotly import optional_imports
1513
from chart_studio.plotly import plotly as py
1614
from unittest import TestCase
15+
import pytest
1716

1817
matplotlylib = optional_imports.get_module("plotly.matplotlylib")
1918

2019
if matplotlylib:
2120
import matplotlib.pyplot as plt
2221

2322

24-
@attr("matplotlib")
23+
@pytest.mark.matplotlib
2524
class PlotMPLTest(TestCase):
2625
def setUp(self):
2726
py.sign_in("PlotlyImageTest", "786r5mecv0", plotly_domain="https://plot.ly")
2827

29-
@raises(_plotly_utils.exceptions.PlotlyGraphObjectError)
3028
def test_update_type_error(self):
3129
fig, ax = plt.subplots()
3230
ax.plot([1, 2, 3])
3331
update = []
34-
py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
32+
with pytest.raises(_plotly_utils.exceptions.PlotlyGraphObjectError):
33+
py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
3534

36-
@raises(KeyError)
3735
def test_update_validation_error(self):
3836
fig, ax = plt.subplots()
3937
ax.plot([1, 2, 3])
4038
update = {"invalid": "anything"}
41-
py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
39+
with pytest.raises(KeyError):
40+
py.plot_mpl(fig, update=update, filename="nosetests", auto_open=False)
4241

43-
@attr("slow")
4442
def test_update(self):
4543
fig, ax = plt.subplots()
4644
ax.plot([1, 2, 3])

Diff for: packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_file/test_file.py

-2
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,12 @@
88
import random
99
import string
1010

11-
from nose.plugins.attrib import attr
1211

1312
from chart_studio import plotly as py
1413
from chart_studio.exceptions import PlotlyRequestError
1514
from chart_studio.tests.utils import PlotlyTestCase
1615

1716

18-
@attr("slow")
1917
class FolderAPITestCase(PlotlyTestCase):
2018
def setUp(self):
2119
super(FolderAPITestCase, self).setUp()

Diff for: packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_figure/test_get_figure.py

-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from unittest import skipIf
1111

1212
import six
13-
from nose.plugins.attrib import attr
1413

1514
import _plotly_utils.exceptions
1615
from chart_studio import exceptions
@@ -38,15 +37,13 @@ def is_trivial(obj):
3837

3938

4039
class GetFigureTest(PlotlyTestCase):
41-
@attr("slow")
4240
def test_get_figure(self):
4341
un = "PlotlyImageTest"
4442
ak = "786r5mecv0"
4543
file_id = 13183
4644
py.sign_in(un, ak)
4745
py.get_figure("PlotlyImageTest", str(file_id))
4846

49-
@attr("slow")
5047
def test_get_figure_with_url(self):
5148
un = "PlotlyImageTest"
5249
ak = "786r5mecv0"
@@ -62,7 +59,6 @@ def test_get_figure_invalid_1(self):
6259
with self.assertRaises(exceptions.PlotlyError):
6360
py.get_figure(url)
6461

65-
@attr("slow")
6662
def test_get_figure_invalid_2(self):
6763
un = "PlotlyImageTest"
6864
ak = "786r5mecv0"
@@ -80,7 +76,6 @@ def test_get_figure_invalid_3(self):
8076
with self.assertRaises(ValueError):
8177
py.get_figure(url)
8278

83-
@attr("slow")
8479
def test_get_figure_does_not_exist(self):
8580
un = "PlotlyImageTest"
8681
ak = "786r5mecv0"
@@ -89,7 +84,6 @@ def test_get_figure_does_not_exist(self):
8984
with self.assertRaises(_plotly_utils.exceptions.PlotlyError):
9085
py.get_figure(url)
9186

92-
@attr("slow")
9387
def test_get_figure_raw(self):
9488
un = "PlotlyImageTest"
9589
ak = "786r5mecv0"

Diff for: packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_get_requests/test_get_requests.py

-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
import requests
1111
import six
12-
from nose.plugins.attrib import attr
1312
import json as _json
1413

1514
from chart_studio.tests.utils import PlotlyTestCase
@@ -25,7 +24,6 @@
2524

2625

2726
class GetRequestsTest(PlotlyTestCase):
28-
@attr("slow")
2927
def test_user_does_not_exist(self):
3028
username = "user_does_not_exist"
3129
api_key = "invalid-apikey"
@@ -47,7 +45,6 @@ def test_user_does_not_exist(self):
4745
self.assertEqual(response.status_code, 404)
4846
self.assertEqual(content["error"], error_message)
4947

50-
@attr("slow")
5148
def test_file_does_not_exist(self):
5249
username = "PlotlyImageTest"
5350
api_key = "786r5mecv0"
@@ -68,7 +65,6 @@ def test_file_does_not_exist(self):
6865
self.assertEqual(response.status_code, 404)
6966
self.assertEqual(content["error"], error_message)
7067

71-
@attr("slow")
7268
def test_wrong_api_key(self): # TODO: does this test the right thing?
7369
username = "PlotlyImageTest"
7470
api_key = "invalid-apikey"
@@ -85,7 +81,6 @@ def test_wrong_api_key(self): # TODO: does this test the right thing?
8581
# Locked File
8682
# TODO
8783

88-
@attr("slow")
8984
def test_private_permission_defined(self):
9085
username = "PlotlyImageTest"
9186
api_key = "786r5mecv0"
@@ -105,7 +100,6 @@ def test_private_permission_defined(self):
105100
# Private File that is shared
106101
# TODO
107102

108-
@attr("slow")
109103
def test_missing_headers(self):
110104
file_owner = "get_test_user"
111105
file_id = 0
@@ -121,7 +115,6 @@ def test_missing_headers(self):
121115
content = _json.loads(response.content.decode("unicode_escape"))
122116
self.assertEqual(response.status_code, 422)
123117

124-
@attr("slow")
125118
def test_valid_request(self):
126119
username = "PlotlyImageTest"
127120
api_key = "786r5mecv0"

Diff for: packages/python/chart-studio/chart_studio/tests/test_plot_ly/test_grid/test_grid.py

-10
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import string
1212
from unittest import skip
1313

14-
from nose.plugins.attrib import attr
1514

1615
from chart_studio import plotly as py
1716
from chart_studio.exceptions import InputError, PlotlyRequestError
@@ -54,19 +53,16 @@ def upload_and_return_grid(self):
5453
return g
5554

5655
# Nominal usage
57-
@attr("slow")
5856
def test_grid_upload(self):
5957
self.upload_and_return_grid()
6058

61-
@attr("slow")
6259
def test_grid_upload_in_new_folder(self):
6360
g = self.get_grid()
6461
path = "new folder: {0}/grid in folder {1}".format(
6562
random_filename(), random_filename()
6663
)
6764
py.grid_ops.upload(g, path, auto_open=False)
6865

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

78-
@attr("slow")
7974
def test_column_append(self):
8075
g = self.upload_and_return_grid()
8176
new_col = Column([1, 5, 3], "new col")
8277
py.grid_ops.append_columns([new_col], grid=g)
8378

84-
@attr("slow")
8579
def test_row_append(self):
8680
g = self.upload_and_return_grid()
8781
new_rows = [[1, 2], [10, 20]]
8882
py.grid_ops.append_rows(new_rows, grid=g)
8983

90-
@attr("slow")
9184
def test_plot_from_grid(self):
9285
g = self.upload_and_return_grid()
9386
url = py.plot(
@@ -97,7 +90,6 @@ def test_plot_from_grid(self):
9790
)
9891
return url, g
9992

100-
@attr("slow")
10193
def test_get_figure_from_references(self):
10294
url, g = self.test_plot_from_grid()
10395
fig = py.get_figure(url)
@@ -143,7 +135,6 @@ def test_row_append_of_non_uploaded_grid(self):
143135
py.grid_ops.append_rows(rows, grid=g)
144136

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

160151
# Test delete
161-
@attr("slow")
162152
def test_delete_grid(self):
163153
g = self.get_grid()
164154
fn = random_filename()

0 commit comments

Comments
 (0)