Skip to content

Commit

Permalink
Make validate_docstrings.py ready for the CI (#23514)
Browse files Browse the repository at this point in the history
* validate_docstrings.py to exit with status code as the number of errors (so, 0 for no errors)

* Implemented different output types for the validate_all, and a prefix to filter which docstrings are validated

* Codifying errors

* Adding --errors parameter to be able to validate only specific errors
  • Loading branch information
datapythonista authored and jorisvandenbossche committed Nov 7, 2018
1 parent 528527b commit 5938ce1
Show file tree
Hide file tree
Showing 2 changed files with 387 additions and 145 deletions.
164 changes: 128 additions & 36 deletions scripts/tests/test_validate_docstrings.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import string
import random
import io
import random
import string
import textwrap
import pytest
import numpy as np

from pandas.util.testing import capture_stderr
import validate_docstrings
validate_one = validate_docstrings.validate_one

from pandas.util.testing import capture_stderr


class GoodDocStrings(object):
"""
Expand Down Expand Up @@ -712,9 +711,9 @@ def test_bad_generic_functions(self, func):
('BadSummaries', 'no_capitalization',
('Summary must start with infinitive verb',)),
('BadSummaries', 'multi_line',
('Summary should fit in a single line.',)),
('Summary should fit in a single line',)),
('BadSummaries', 'two_paragraph_multi_line',
('Summary should fit in a single line.',)),
('Summary should fit in a single line',)),
# Parameters tests
('BadParameters', 'missing_params',
('Parameters {**kwargs} not documented',)),
Expand Down Expand Up @@ -753,66 +752,67 @@ def test_bad_generic_functions(self, func):
marks=pytest.mark.xfail),
# Examples tests
('BadGenericDocStrings', 'method',
('numpy does not need to be imported in the examples',)),
('Do not import numpy, as it is imported automatically',)),
('BadGenericDocStrings', 'method',
('pandas does not need to be imported in the examples',)),
('Do not import pandas, as it is imported automatically',)),
# See Also tests
('BadSeeAlso', 'prefix_pandas',
('pandas.Series.rename in `See Also` section '
'does not need `pandas` prefix',)),
# Examples tests
('BadExamples', 'unused_import',
('1 F401 \'pandas as pdf\' imported but unused',)),
("flake8 error: F401 'pandas as pdf' imported but unused",)),
('BadExamples', 'indentation_is_not_a_multiple_of_four',
('1 E111 indentation is not a multiple of four',)),
('flake8 error: E111 indentation is not a multiple of four',)),
('BadExamples', 'missing_whitespace_around_arithmetic_operator',
('1 E226 missing whitespace around arithmetic operator',)),
('flake8 error: '
'E226 missing whitespace around arithmetic operator',)),
('BadExamples', 'missing_whitespace_after_comma',
('3 E231 missing whitespace after \',\'',)),
("flake8 error: E231 missing whitespace after ',' (3 times)",)),
])
def test_bad_examples(self, capsys, klass, func, msgs):
result = validate_one(self._import_path(klass=klass, func=func))
for msg in msgs:
assert msg in ' '.join(result['errors'])
assert msg in ' '.join(err[1] for err in result['errors'])


class ApiItems(object):
@property
def api_doc(self):
return io.StringIO('''
.. currentmodule:: itertools
return textwrap.dedent(io.StringIO('''
.. currentmodule:: itertools
Itertools
---------
Itertools
---------
Infinite
~~~~~~~~
Infinite
~~~~~~~~
.. autosummary::
.. autosummary::
cycle
count
cycle
count
Finite
~~~~~~
Finite
~~~~~~
.. autosummary::
.. autosummary::
chain
chain
.. currentmodule:: random
.. currentmodule:: random
Random
------
Random
------
All
~~~
All
~~~
.. autosummary::
.. autosummary::
seed
randint
''')
seed
randint
'''))

@pytest.mark.parametrize('idx,name', [(0, 'itertools.cycle'),
(1, 'itertools.count'),
Expand Down Expand Up @@ -850,3 +850,95 @@ def test_item_section(self, idx, section):
def test_item_subsection(self, idx, subsection):
result = list(validate_docstrings.get_api_items(self.api_doc))
assert result[idx][3] == subsection


class MainFunction(object):
def test_num_errors_for_validate_one(self, monkeypatch):
monkeypatch.setattr(
validate_docstrings, 'validate_one',
lambda func_name: {'docstring': 'docstring1',
'errors': [('ER01', 'err desc'),
('ER02', 'err desc')
('ER03', 'err desc')],
'warnings': [],
'examples_errors': ''})
num_errors = validate_docstrings.main(func_name='docstring1',
prefix=None,
errors=[],
output_format='default')
assert num_errors == 3

def test_no_num_errors_for_validate_one(self, monkeypatch):
monkeypatch.setattr(
validate_docstrings, 'validate_one',
lambda func_name: {'docstring': 'docstring1',
'errors': [],
'warnings': [('WN01', 'warn desc')],
'examples_errors': ''})
num_errors = validate_docstrings.main(func_name='docstring1',
prefix=None,
errors=[],
output_format='default')
assert num_errors == 0

def test_num_errors_for_validate_all(self, monkeypatch):
monkeypatch.setattr(
validate_docstrings, 'validate_all',
lambda: {'docstring1': {'errors': [('ER01', 'err desc'),
('ER02', 'err desc'),
('ER03', 'err desc')]},
'docstring2': {'errors': [('ER04', 'err desc'),
('ER05', 'err desc')]}})
num_errors = validate_docstrings.main(func_name=None,
prefix=None,
errors=[],
output_format='default')
assert num_errors == 5

def test_no_num_errors_for_validate_all(self, monkeypatch):
monkeypatch.setattr(
validate_docstrings, 'validate_all',
lambda: {'docstring1': {'errors': [],
'warnings': [('WN01', 'warn desc')]},
'docstring2': {'errors': []}})
num_errors = validate_docstrings.main(func_name=None,
prefix=None,
errors=[],
output_format='default')
assert num_errors == 0

def test_prefix_param_filters_docstrings(self, monkeypatch):
monkeypatch.setattr(
validate_docstrings, 'validate_all',
lambda: {'Series.foo': {'errors': [('ER01', 'err desc'),
('ER02', 'err desc'),
('ER03', 'err desc')]},
'DataFrame.bar': {'errors': [('ER04', 'err desc'),
('ER05', 'err desc')]},
'Series.foobar': {'errors': [('ER06', 'err desc')]}})
num_errors = validate_docstrings.main(func_name=None,
prefix='Series.',
errors=[],
output_format='default')
assert num_errors == 4

def test_errors_param_filters_errors(self, monkeypatch):
monkeypatch.setattr(
validate_docstrings, 'validate_all',
lambda: {'Series.foo': {'errors': [('ER01', 'err desc'),
('ER02', 'err desc'),
('ER03', 'err desc')]},
'DataFrame.bar': {'errors': [('ER01', 'err desc'),
('ER02', 'err desc')]},
'Series.foobar': {'errors': [('ER01', 'err desc')]}})
num_errors = validate_docstrings.main(func_name=None,
prefix=None,
errors=['E01'],
output_format='default')
assert num_errors == 3

num_errors = validate_docstrings.main(func_name=None,
prefix=None,
errors=['E03'],
output_format='default')
assert num_errors == 1
Loading

0 comments on commit 5938ce1

Please sign in to comment.