Skip to content

Commit 1a2f0b1

Browse files
datapythonistatm9k1
authored andcommitted
Fixes to make validate_docstrings.py not generate warnings or unwanted output (pandas-dev#23552)
1 parent 825dc54 commit 1a2f0b1

File tree

8 files changed

+112
-115
lines changed

8 files changed

+112
-115
lines changed

pandas/core/generic.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5100,7 +5100,7 @@ def get_ftype_counts(self):
51005100
1 b 2 2.0
51015101
2 c 3 3.0
51025102
5103-
>>> df.get_ftype_counts()
5103+
>>> df.get_ftype_counts() # doctest: +SKIP
51045104
float64:dense 1
51055105
int64:dense 1
51065106
object:dense 1

pandas/core/indexes/base.py

+5-9
Original file line numberDiff line numberDiff line change
@@ -1875,35 +1875,31 @@ def get_duplicates(self):
18751875
18761876
Works on different Index of types.
18771877
1878-
>>> pd.Index([1, 2, 2, 3, 3, 3, 4]).get_duplicates()
1878+
>>> pd.Index([1, 2, 2, 3, 3, 3, 4]).get_duplicates() # doctest: +SKIP
18791879
[2, 3]
1880-
>>> pd.Index([1., 2., 2., 3., 3., 3., 4.]).get_duplicates()
1881-
[2.0, 3.0]
1882-
>>> pd.Index(['a', 'b', 'b', 'c', 'c', 'c', 'd']).get_duplicates()
1883-
['b', 'c']
18841880
18851881
Note that for a DatetimeIndex, it does not return a list but a new
18861882
DatetimeIndex:
18871883
18881884
>>> dates = pd.to_datetime(['2018-01-01', '2018-01-02', '2018-01-03',
18891885
... '2018-01-03', '2018-01-04', '2018-01-04'],
18901886
... format='%Y-%m-%d')
1891-
>>> pd.Index(dates).get_duplicates()
1887+
>>> pd.Index(dates).get_duplicates() # doctest: +SKIP
18921888
DatetimeIndex(['2018-01-03', '2018-01-04'],
18931889
dtype='datetime64[ns]', freq=None)
18941890
18951891
Sorts duplicated elements even when indexes are unordered.
18961892
1897-
>>> pd.Index([1, 2, 3, 2, 3, 4, 3]).get_duplicates()
1893+
>>> pd.Index([1, 2, 3, 2, 3, 4, 3]).get_duplicates() # doctest: +SKIP
18981894
[2, 3]
18991895
19001896
Return empty array-like structure when all elements are unique.
19011897
1902-
>>> pd.Index([1, 2, 3, 4]).get_duplicates()
1898+
>>> pd.Index([1, 2, 3, 4]).get_duplicates() # doctest: +SKIP
19031899
[]
19041900
>>> dates = pd.to_datetime(['2018-01-01', '2018-01-02', '2018-01-03'],
19051901
... format='%Y-%m-%d')
1906-
>>> pd.Index(dates).get_duplicates()
1902+
>>> pd.Index(dates).get_duplicates() # doctest: +SKIP
19071903
DatetimeIndex([], dtype='datetime64[ns]', freq=None)
19081904
"""
19091905
warnings.warn("'get_duplicates' is deprecated and will be removed in "

pandas/core/panel.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1013,21 +1013,21 @@ def apply(self, func, axis='major', **kwargs):
10131013
10141014
Returns a Panel with the square root of each element
10151015
1016-
>>> p = pd.Panel(np.random.rand(4,3,2))
1016+
>>> p = pd.Panel(np.random.rand(4, 3, 2)) # doctest: +SKIP
10171017
>>> p.apply(np.sqrt)
10181018
10191019
Equivalent to p.sum(1), returning a DataFrame
10201020
1021-
>>> p.apply(lambda x: x.sum(), axis=1)
1021+
>>> p.apply(lambda x: x.sum(), axis=1) # doctest: +SKIP
10221022
10231023
Equivalent to previous:
10241024
1025-
>>> p.apply(lambda x: x.sum(), axis='major')
1025+
>>> p.apply(lambda x: x.sum(), axis='major') # doctest: +SKIP
10261026
10271027
Return the shapes of each DataFrame over axis 2 (i.e the shapes of
10281028
items x major), as a Series
10291029
1030-
>>> p.apply(lambda x: x.shape, axis=(0,1))
1030+
>>> p.apply(lambda x: x.shape, axis=(0,1)) # doctest: +SKIP
10311031
10321032
Returns
10331033
-------

pandas/core/strings.py

-7
Original file line numberDiff line numberDiff line change
@@ -2156,13 +2156,6 @@ def cat(self, others=None, sep=None, na_rep=None, join=None):
21562156
`join`-keyword works as in other methods.
21572157
21582158
>>> t = pd.Series(['d', 'a', 'e', 'c'], index=[3, 0, 4, 2])
2159-
>>> s.str.cat(t, join=None, na_rep='-')
2160-
0 ad
2161-
1 ba
2162-
2 -e
2163-
3 dc
2164-
dtype: object
2165-
>>>
21662159
>>> s.str.cat(t, join='left', na_rep='-')
21672160
0 aa
21682161
1 b-

pandas/errors/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ class ParserWarning(Warning):
133133
>>> csv = u'''a;b;c
134134
... 1;1,8
135135
... 1;2,1'''
136-
>>> df = pd.read_csv(io.StringIO(csv), sep='[;,]')
136+
>>> df = pd.read_csv(io.StringIO(csv), sep='[;,]') # doctest: +SKIP
137137
... # ParserWarning: Falling back to the 'python' engine...
138138
139139
Adding `engine='python'` to `pd.read_csv` removes the Warning:

pandas/plotting/_misc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def radviz(frame, class_column, ax=None, color=None, colormap=None, **kwds):
206206
... 'versicolor', 'setosa', 'virginica',
207207
... 'setosa']
208208
... })
209-
>>> rad_viz = pd.plotting.radviz(df, 'Category')
209+
>>> rad_viz = pd.plotting.radviz(df, 'Category') # doctest: +SKIP
210210
"""
211211
import matplotlib.pyplot as plt
212212
import matplotlib.patches as patches
@@ -407,7 +407,7 @@ def bootstrap_plot(series, fig=None, size=50, samples=500, **kwds):
407407
:context: close-figs
408408
409409
>>> s = pd.Series(np.random.uniform(size=100))
410-
>>> fig = pd.plotting.bootstrap_plot(s)
410+
>>> fig = pd.plotting.bootstrap_plot(s) # doctest: +SKIP
411411
"""
412412
import random
413413
import matplotlib.pyplot as plt

scripts/tests/test_validate_docstrings.py

+82-85
Original file line numberDiff line numberDiff line change
@@ -785,10 +785,10 @@ def test_bad_examples(self, capsys, klass, func, msgs):
785785
assert msg in ' '.join(err[1] for err in result['errors'])
786786

787787

788-
class ApiItems(object):
788+
class TestApiItems(object):
789789
@property
790790
def api_doc(self):
791-
return textwrap.dedent(io.StringIO('''
791+
return io.StringIO(textwrap.dedent('''
792792
.. currentmodule:: itertools
793793
794794
Itertools
@@ -861,93 +861,90 @@ def test_item_subsection(self, idx, subsection):
861861
assert result[idx][3] == subsection
862862

863863

864-
class MainFunction(object):
865-
def test_num_errors_for_validate_one(self, monkeypatch):
864+
class TestMainFunction(object):
865+
def test_exit_status_for_validate_one(self, monkeypatch):
866866
monkeypatch.setattr(
867-
validate_docstrings, 'validate_one',
868-
lambda func_name: {'docstring': 'docstring1',
869-
'errors': [('ER01', 'err desc'),
870-
('ER02', 'err desc')
871-
('ER03', 'err desc')],
872-
'warnings': [],
873-
'examples_errors': ''})
874-
num_errors = validate_docstrings.main(func_name='docstring1',
875-
prefix=None,
876-
errors=[],
877-
output_format='default')
878-
assert num_errors == 3
879-
880-
def test_no_num_errors_for_validate_one(self, monkeypatch):
881-
monkeypatch.setattr(
882-
validate_docstrings, 'validate_one',
883-
lambda func_name: {'docstring': 'docstring1',
884-
'errors': [],
885-
'warnings': [('WN01', 'warn desc')],
886-
'examples_errors': ''})
887-
num_errors = validate_docstrings.main(func_name='docstring1',
888-
prefix=None,
889-
errors=[],
890-
output_format='default')
891-
assert num_errors == 0
892-
893-
def test_num_errors_for_validate_all(self, monkeypatch):
867+
validate_docstrings, 'validate_one', lambda func_name: {
868+
'docstring': 'docstring1',
869+
'errors': [('ER01', 'err desc'),
870+
('ER02', 'err desc'),
871+
('ER03', 'err desc')],
872+
'warnings': [],
873+
'examples_errors': ''})
874+
exit_status = validate_docstrings.main(func_name='docstring1',
875+
prefix=None,
876+
errors=[],
877+
output_format='default')
878+
assert exit_status == 0
879+
880+
def test_exit_status_errors_for_validate_all(self, monkeypatch):
894881
monkeypatch.setattr(
895-
validate_docstrings, 'validate_all',
896-
lambda: {'docstring1': {'errors': [('ER01', 'err desc'),
897-
('ER02', 'err desc'),
898-
('ER03', 'err desc')]},
899-
'docstring2': {'errors': [('ER04', 'err desc'),
900-
('ER05', 'err desc')]}})
901-
num_errors = validate_docstrings.main(func_name=None,
902-
prefix=None,
903-
errors=[],
904-
output_format='default')
905-
assert num_errors == 5
906-
907-
def test_no_num_errors_for_validate_all(self, monkeypatch):
882+
validate_docstrings, 'validate_all', lambda prefix: {
883+
'docstring1': {'errors': [('ER01', 'err desc'),
884+
('ER02', 'err desc'),
885+
('ER03', 'err desc')],
886+
'file': 'module1.py',
887+
'file_line': 23},
888+
'docstring2': {'errors': [('ER04', 'err desc'),
889+
('ER05', 'err desc')],
890+
'file': 'module2.py',
891+
'file_line': 925}})
892+
exit_status = validate_docstrings.main(func_name=None,
893+
prefix=None,
894+
errors=[],
895+
output_format='default')
896+
assert exit_status == 5
897+
898+
def test_no_exit_status_noerrors_for_validate_all(self, monkeypatch):
908899
monkeypatch.setattr(
909-
validate_docstrings, 'validate_all',
910-
lambda: {'docstring1': {'errors': [],
911-
'warnings': [('WN01', 'warn desc')]},
912-
'docstring2': {'errors': []}})
913-
num_errors = validate_docstrings.main(func_name=None,
914-
prefix=None,
915-
errors=[],
916-
output_format='default')
917-
assert num_errors == 0
918-
919-
def test_prefix_param_filters_docstrings(self, monkeypatch):
900+
validate_docstrings, 'validate_all', lambda prefix: {
901+
'docstring1': {'errors': [],
902+
'warnings': [('WN01', 'warn desc')]},
903+
'docstring2': {'errors': []}})
904+
exit_status = validate_docstrings.main(func_name=None,
905+
prefix=None,
906+
errors=[],
907+
output_format='default')
908+
assert exit_status == 0
909+
910+
def test_exit_status_for_validate_all_json(self, monkeypatch):
911+
print('EXECUTED')
920912
monkeypatch.setattr(
921-
validate_docstrings, 'validate_all',
922-
lambda: {'Series.foo': {'errors': [('ER01', 'err desc'),
923-
('ER02', 'err desc'),
924-
('ER03', 'err desc')]},
925-
'DataFrame.bar': {'errors': [('ER04', 'err desc'),
926-
('ER05', 'err desc')]},
927-
'Series.foobar': {'errors': [('ER06', 'err desc')]}})
928-
num_errors = validate_docstrings.main(func_name=None,
929-
prefix='Series.',
930-
errors=[],
931-
output_format='default')
932-
assert num_errors == 4
913+
validate_docstrings, 'validate_all', lambda prefix: {
914+
'docstring1': {'errors': [('ER01', 'err desc'),
915+
('ER02', 'err desc'),
916+
('ER03', 'err desc')]},
917+
'docstring2': {'errors': [('ER04', 'err desc'),
918+
('ER05', 'err desc')]}})
919+
exit_status = validate_docstrings.main(func_name=None,
920+
prefix=None,
921+
errors=[],
922+
output_format='json')
923+
assert exit_status == 0
933924

934925
def test_errors_param_filters_errors(self, monkeypatch):
935926
monkeypatch.setattr(
936-
validate_docstrings, 'validate_all',
937-
lambda: {'Series.foo': {'errors': [('ER01', 'err desc'),
938-
('ER02', 'err desc'),
939-
('ER03', 'err desc')]},
940-
'DataFrame.bar': {'errors': [('ER01', 'err desc'),
941-
('ER02', 'err desc')]},
942-
'Series.foobar': {'errors': [('ER01', 'err desc')]}})
943-
num_errors = validate_docstrings.main(func_name=None,
944-
prefix=None,
945-
errors=['E01'],
946-
output_format='default')
947-
assert num_errors == 3
948-
949-
num_errors = validate_docstrings.main(func_name=None,
950-
prefix=None,
951-
errors=['E03'],
952-
output_format='default')
953-
assert num_errors == 1
927+
validate_docstrings, 'validate_all', lambda prefix: {
928+
'Series.foo': {'errors': [('ER01', 'err desc'),
929+
('ER02', 'err desc'),
930+
('ER03', 'err desc')],
931+
'file': 'series.py',
932+
'file_line': 142},
933+
'DataFrame.bar': {'errors': [('ER01', 'err desc'),
934+
('ER02', 'err desc')],
935+
'file': 'frame.py',
936+
'file_line': 598},
937+
'Series.foobar': {'errors': [('ER01', 'err desc')],
938+
'file': 'series.py',
939+
'file_line': 279}})
940+
exit_status = validate_docstrings.main(func_name=None,
941+
prefix=None,
942+
errors=['ER01'],
943+
output_format='default')
944+
assert exit_status == 3
945+
946+
exit_status = validate_docstrings.main(func_name=None,
947+
prefix=None,
948+
errors=['ER03'],
949+
output_format='default')
950+
assert exit_status == 1

scripts/validate_docstrings.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@
3232
from io import StringIO
3333
except ImportError:
3434
from cStringIO import StringIO
35+
36+
# Template backend makes matplotlib to not plot anything. This is useful
37+
# to avoid that plot windows are open from the doctests while running the
38+
# script. Setting here before matplotlib is loaded.
39+
# We don't warn for the number of open plots, as none is actually being opened
40+
os.environ['MPLBACKEND'] = 'Template'
41+
import matplotlib
42+
matplotlib.rc('figure', max_open_warning=10000)
43+
3544
import numpy
3645

3746
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -505,6 +514,9 @@ def validate_pep8(self):
505514
file.flush()
506515
application.run_checks([file.name])
507516

517+
# We need this to avoid flake8 printing the names of the files to
518+
# the standard output
519+
application.formatter.write = lambda line, source: None
508520
application.report()
509521

510522
yield from application.guide.stats.statistics_for('')
@@ -733,6 +745,7 @@ def header(title, width=80, char='#'):
733745
return '\n{full_line}\n{title_line}\n{full_line}\n\n'.format(
734746
full_line=full_line, title_line=title_line)
735747

748+
exit_status = 0
736749
if func_name is None:
737750
result = validate_all(prefix)
738751

@@ -751,28 +764,26 @@ def header(title, width=80, char='#'):
751764
raise ValueError('Unknown output_format "{}"'.format(
752765
output_format))
753766

754-
num_errors, output = 0, ''
767+
output = ''
755768
for name, res in result.items():
756769
for err_code, err_desc in res['errors']:
757770
# The script would be faster if instead of filtering the
758771
# errors after validating them, it didn't validate them
759772
# initially. But that would complicate the code too much
760773
if errors and err_code not in errors:
761774
continue
762-
num_errors += 1
775+
exit_status += 1
763776
output += output_format.format(
764777
name=name,
765778
path=res['file'],
766779
row=res['file_line'],
767780
code=err_code,
768781
text='{}: {}'.format(name, err_desc))
769782

770-
sys.stderr.write(output)
783+
sys.stdout.write(output)
771784

772785
else:
773786
result = validate_one(func_name)
774-
num_errors = len(result['errors'])
775-
776787
sys.stderr.write(header('Docstring ({})'.format(func_name)))
777788
sys.stderr.write('{}\n'.format(result['docstring']))
778789
sys.stderr.write(header('Validation'))
@@ -799,7 +810,7 @@ def header(title, width=80, char='#'):
799810
sys.stderr.write(header('Doctests'))
800811
sys.stderr.write(result['examples_errors'])
801812

802-
return num_errors
813+
return exit_status
803814

804815

805816
if __name__ == '__main__':

0 commit comments

Comments
 (0)