Skip to content

Commit 17d04ed

Browse files
datapythonistatm9k1
authored andcommitted
Make validate_docstrings.py ready for the CI (pandas-dev#23514)
* 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
1 parent ed61457 commit 17d04ed

File tree

2 files changed

+387
-145
lines changed

2 files changed

+387
-145
lines changed

scripts/tests/test_validate_docstrings.py

+128-36
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
1-
import string
2-
import random
31
import io
2+
import random
3+
import string
4+
import textwrap
45
import pytest
56
import numpy as np
6-
7+
from pandas.util.testing import capture_stderr
78
import validate_docstrings
89
validate_one = validate_docstrings.validate_one
910

10-
from pandas.util.testing import capture_stderr
11-
1211

1312
class GoodDocStrings(object):
1413
"""
@@ -712,9 +711,9 @@ def test_bad_generic_functions(self, func):
712711
('BadSummaries', 'no_capitalization',
713712
('Summary must start with infinitive verb',)),
714713
('BadSummaries', 'multi_line',
715-
('Summary should fit in a single line.',)),
714+
('Summary should fit in a single line',)),
716715
('BadSummaries', 'two_paragraph_multi_line',
717-
('Summary should fit in a single line.',)),
716+
('Summary should fit in a single line',)),
718717
# Parameters tests
719718
('BadParameters', 'missing_params',
720719
('Parameters {**kwargs} not documented',)),
@@ -753,66 +752,67 @@ def test_bad_generic_functions(self, func):
753752
marks=pytest.mark.xfail),
754753
# Examples tests
755754
('BadGenericDocStrings', 'method',
756-
('numpy does not need to be imported in the examples',)),
755+
('Do not import numpy, as it is imported automatically',)),
757756
('BadGenericDocStrings', 'method',
758-
('pandas does not need to be imported in the examples',)),
757+
('Do not import pandas, as it is imported automatically',)),
759758
# See Also tests
760759
('BadSeeAlso', 'prefix_pandas',
761760
('pandas.Series.rename in `See Also` section '
762761
'does not need `pandas` prefix',)),
763762
# Examples tests
764763
('BadExamples', 'unused_import',
765-
('1 F401 \'pandas as pdf\' imported but unused',)),
764+
("flake8 error: F401 'pandas as pdf' imported but unused",)),
766765
('BadExamples', 'indentation_is_not_a_multiple_of_four',
767-
('1 E111 indentation is not a multiple of four',)),
766+
('flake8 error: E111 indentation is not a multiple of four',)),
768767
('BadExamples', 'missing_whitespace_around_arithmetic_operator',
769-
('1 E226 missing whitespace around arithmetic operator',)),
768+
('flake8 error: '
769+
'E226 missing whitespace around arithmetic operator',)),
770770
('BadExamples', 'missing_whitespace_after_comma',
771-
('3 E231 missing whitespace after \',\'',)),
771+
("flake8 error: E231 missing whitespace after ',' (3 times)",)),
772772
])
773773
def test_bad_examples(self, capsys, klass, func, msgs):
774774
result = validate_one(self._import_path(klass=klass, func=func))
775775
for msg in msgs:
776-
assert msg in ' '.join(result['errors'])
776+
assert msg in ' '.join(err[1] for err in result['errors'])
777777

778778

779779
class ApiItems(object):
780780
@property
781781
def api_doc(self):
782-
return io.StringIO('''
783-
.. currentmodule:: itertools
782+
return textwrap.dedent(io.StringIO('''
783+
.. currentmodule:: itertools
784784
785-
Itertools
786-
---------
785+
Itertools
786+
---------
787787
788-
Infinite
789-
~~~~~~~~
788+
Infinite
789+
~~~~~~~~
790790
791-
.. autosummary::
791+
.. autosummary::
792792
793-
cycle
794-
count
793+
cycle
794+
count
795795
796-
Finite
797-
~~~~~~
796+
Finite
797+
~~~~~~
798798
799-
.. autosummary::
799+
.. autosummary::
800800
801-
chain
801+
chain
802802
803-
.. currentmodule:: random
803+
.. currentmodule:: random
804804
805-
Random
806-
------
805+
Random
806+
------
807807
808-
All
809-
~~~
808+
All
809+
~~~
810810
811-
.. autosummary::
811+
.. autosummary::
812812
813-
seed
814-
randint
815-
''')
813+
seed
814+
randint
815+
'''))
816816

817817
@pytest.mark.parametrize('idx,name', [(0, 'itertools.cycle'),
818818
(1, 'itertools.count'),
@@ -850,3 +850,95 @@ def test_item_section(self, idx, section):
850850
def test_item_subsection(self, idx, subsection):
851851
result = list(validate_docstrings.get_api_items(self.api_doc))
852852
assert result[idx][3] == subsection
853+
854+
855+
class MainFunction(object):
856+
def test_num_errors_for_validate_one(self, monkeypatch):
857+
monkeypatch.setattr(
858+
validate_docstrings, 'validate_one',
859+
lambda func_name: {'docstring': 'docstring1',
860+
'errors': [('ER01', 'err desc'),
861+
('ER02', 'err desc')
862+
('ER03', 'err desc')],
863+
'warnings': [],
864+
'examples_errors': ''})
865+
num_errors = validate_docstrings.main(func_name='docstring1',
866+
prefix=None,
867+
errors=[],
868+
output_format='default')
869+
assert num_errors == 3
870+
871+
def test_no_num_errors_for_validate_one(self, monkeypatch):
872+
monkeypatch.setattr(
873+
validate_docstrings, 'validate_one',
874+
lambda func_name: {'docstring': 'docstring1',
875+
'errors': [],
876+
'warnings': [('WN01', 'warn desc')],
877+
'examples_errors': ''})
878+
num_errors = validate_docstrings.main(func_name='docstring1',
879+
prefix=None,
880+
errors=[],
881+
output_format='default')
882+
assert num_errors == 0
883+
884+
def test_num_errors_for_validate_all(self, monkeypatch):
885+
monkeypatch.setattr(
886+
validate_docstrings, 'validate_all',
887+
lambda: {'docstring1': {'errors': [('ER01', 'err desc'),
888+
('ER02', 'err desc'),
889+
('ER03', 'err desc')]},
890+
'docstring2': {'errors': [('ER04', 'err desc'),
891+
('ER05', 'err desc')]}})
892+
num_errors = validate_docstrings.main(func_name=None,
893+
prefix=None,
894+
errors=[],
895+
output_format='default')
896+
assert num_errors == 5
897+
898+
def test_no_num_errors_for_validate_all(self, monkeypatch):
899+
monkeypatch.setattr(
900+
validate_docstrings, 'validate_all',
901+
lambda: {'docstring1': {'errors': [],
902+
'warnings': [('WN01', 'warn desc')]},
903+
'docstring2': {'errors': []}})
904+
num_errors = validate_docstrings.main(func_name=None,
905+
prefix=None,
906+
errors=[],
907+
output_format='default')
908+
assert num_errors == 0
909+
910+
def test_prefix_param_filters_docstrings(self, monkeypatch):
911+
monkeypatch.setattr(
912+
validate_docstrings, 'validate_all',
913+
lambda: {'Series.foo': {'errors': [('ER01', 'err desc'),
914+
('ER02', 'err desc'),
915+
('ER03', 'err desc')]},
916+
'DataFrame.bar': {'errors': [('ER04', 'err desc'),
917+
('ER05', 'err desc')]},
918+
'Series.foobar': {'errors': [('ER06', 'err desc')]}})
919+
num_errors = validate_docstrings.main(func_name=None,
920+
prefix='Series.',
921+
errors=[],
922+
output_format='default')
923+
assert num_errors == 4
924+
925+
def test_errors_param_filters_errors(self, monkeypatch):
926+
monkeypatch.setattr(
927+
validate_docstrings, 'validate_all',
928+
lambda: {'Series.foo': {'errors': [('ER01', 'err desc'),
929+
('ER02', 'err desc'),
930+
('ER03', 'err desc')]},
931+
'DataFrame.bar': {'errors': [('ER01', 'err desc'),
932+
('ER02', 'err desc')]},
933+
'Series.foobar': {'errors': [('ER01', 'err desc')]}})
934+
num_errors = validate_docstrings.main(func_name=None,
935+
prefix=None,
936+
errors=['E01'],
937+
output_format='default')
938+
assert num_errors == 3
939+
940+
num_errors = validate_docstrings.main(func_name=None,
941+
prefix=None,
942+
errors=['E03'],
943+
output_format='default')
944+
assert num_errors == 1

0 commit comments

Comments
 (0)