From 9c09bf176ec63c6eef4e2ffbdb19b435b22d8029 Mon Sep 17 00:00:00 2001 From: Fabian Haase Date: Thu, 1 Nov 2018 12:48:14 +0100 Subject: [PATCH] Added test and slimmed PR * added test * simplified temporary file usage * included flake8 by calling application directly * removed doctests from setup.cfg Signed-off-by: Fabian Haase --- scripts/tests/test_validate_docstrings.py | 30 +++++++++++++- scripts/validate_docstrings.py | 48 +++++++++++------------ setup.cfg | 22 ----------- 3 files changed, 52 insertions(+), 48 deletions(-) diff --git a/scripts/tests/test_validate_docstrings.py b/scripts/tests/test_validate_docstrings.py index 1276e5742e9ea6..2047cf9d5f8ff6 100644 --- a/scripts/tests/test_validate_docstrings.py +++ b/scripts/tests/test_validate_docstrings.py @@ -587,6 +587,29 @@ def prefix_pandas(self): pass +class BadExamples(object): + + def doctest(self): + """ + Return whether each value contains `pat`. + + Examples + -------- + >>> import pandas as pd + >>> df = pd.DataFrame(np.ones((3, 3)), + ... columns=('a', 'b', 'c')) + >>> df.all(1) + 0 True + 1 True + 2 True + dtype: bool + + >>> df.all(bool_only=True) + Series([], dtype: bool) + """ + pass + + class TestValidator(object): def _import_path(self, klass=None, func=None): @@ -706,10 +729,13 @@ def test_bad_generic_functions(self, func): # See Also tests ('BadSeeAlso', 'prefix_pandas', ('pandas.Series.rename in `See Also` section ' - 'does not need `pandas` prefix',)) + 'does not need `pandas` prefix',)), + # Examples tests + ('BadExamples', 'doctest', + ('1 F821 undefined name \'np\'',)) ]) def test_bad_examples(self, capsys, klass, func, msgs): - result = validate_one(self._import_path(klass=klass, func=func)) # noqa:F821 + result = validate_one(self._import_path(klass=klass, func=func)) for msg in msgs: assert msg in ' '.join(result['errors']) diff --git a/scripts/validate_docstrings.py b/scripts/validate_docstrings.py index c3645c90fb2836..b284014e7254d7 100755 --- a/scripts/validate_docstrings.py +++ b/scripts/validate_docstrings.py @@ -24,9 +24,10 @@ import inspect import importlib import doctest +import tempfile from contextlib import contextmanager -from flake8.api import legacy as flake8 +from flake8.main.application import Application as Flake8 try: from io import StringIO @@ -44,6 +45,7 @@ from numpydoc.docscrape import NumpyDocString from pandas.io.formats.printing import pprint_thing + PRIVATE_CLASSES = ['NDFrame', 'IndexOpsMixin'] DIRECTIVES = ['versionadded', 'versionchanged', 'deprecated'] @@ -336,10 +338,16 @@ def parameter_mismatches(self): @property def pep8_violations(self): - with self._file_representation() as filename: - style_guide = flake8.get_style_guide(doctests=True) - report = style_guide.input_file(filename=filename) - return report.get_statistics('') + with self._file_representation() as file: + application = Flake8() + application.initialize(["--doctests"]) + application.run_checks([file.name]) + application.report() + stats = application.guide.stats + return [ + "{} {} {}".format(s.count, s.error_code, s.message) + for s in stats.statistics_for('') + ] @contextmanager def _file_representation(self): @@ -347,29 +355,21 @@ def _file_representation(self): Temporarily creates file with current function inside. The signature and body are **not** included. - :returns filename of tmp file + :returns file """ create_function = 'def {name}():\n' \ ' """{doc}"""\n' \ ' pass\n' - tmp_dir = os.path.join(BASE_PATH, 'build', 'validate_docstring') - os.makedirs(tmp_dir, exist_ok=True) - - filename = os.path.join(tmp_dir, self.name + '.py') - with open(filename, 'w') as f: - name = self.name.split('.')[-1] - lines = self.clean_doc.split("\n") - indented_lines = [(' ' * 4) + line if line else '' - for line in lines[1:]] - doc = '\n'.join([lines[0], *indented_lines]) - - f.write(create_function.format(name=name, doc=doc)) - try: - yield filename - finally: - os.remove(filename) - os.rmdir(tmp_dir) + name = self.name.split('.')[-1] + lines = self.clean_doc.split("\n") + indented_lines = [(' ' * 4) + line if line else '' + for line in lines[1:]] + doc = '\n'.join([lines[0], *indented_lines]) + with tempfile.NamedTemporaryFile(mode='w', suffix='.py') as file: + file.write(create_function.format(name=name, doc=doc)) + file.flush() + yield file @property def correct_parameters(self): @@ -532,7 +532,7 @@ def validate_one(func_name): pep8_errs = doc.pep8_violations if pep8_errs: - errs.append('Errors in doctest sections') + errs.append('Errors in doctests') for pep8_err in pep8_errs: errs.append('\t{}'.format(pep8_err)) diff --git a/setup.cfg b/setup.cfg index 34597947f69bc9..edd3b507cb1837 100644 --- a/setup.cfg +++ b/setup.cfg @@ -28,28 +28,6 @@ exclude = doc/temp/*.py, .eggs/*.py, versioneer.py - .tox - .git - -doctests = True -#TODO fix doctests -exclude_from_doctest = - ./pandas/_libs - ./pandas/api - ./pandas/compat - ./pandas/core - ./pandas/errors - ./pandas/io - ./pandas/plotting - ./pandas/tests - ./pandas/tseries - ./pandas/util - -[flake8-rst] -ignore = - F821, # undefined name - W391, # blank line at end of file [Seems to be a bug (v0.4.1)] - [yapf] based_on_style = pep8