Repository: pandas-dev/pandas

Issue:
CI: Add --ignore-deprecated to validate_docstrings.py
The script `scripts/validate_docstrings.py` returns the list of errors in the docstrings. We are using it to get the list of things to fix, and to check in the CI that no more mistakes are added, after the errors are fixed. See for example #23630.

As we don't really want to spend time fixing the docstrings that will be removed soon, it would be useful to add an argument to the script `--ignore-deprecated` that skips the functions/methods that are marked as deprecated (see `Docstring.deprecated`).

Things to note:
- When deprecated docstrings are skipped, they should not be displayed in the output of the script, and also not counted in the exit status of the script (so, the script should finish with exit status 0 if `--ignore-deprecated` is set and only deprecated functions are wrong).
- We should add at least one test to make sure the new argument works as expected.


Discussion:
i will give a try...
Sure @charlesdong1991, please do.

Resolving patch:
diff --git a/scripts/validate_docstrings.py b/scripts/validate_docstrings.py
--- a/scripts/validate_docstrings.py
+++ b/scripts/validate_docstrings.py
@@ -722,7 +722,7 @@ def validate_one(func_name):
             'examples_errors': examples_errs}
 
 
-def validate_all(prefix):
+def validate_all(prefix, ignore_deprecated=False):
     """
     Execute the validation of all docstrings, and return a dict with the
     results.
@@ -732,6 +732,8 @@ def validate_all(prefix):
     prefix : str or None
         If provided, only the docstrings that start with this pattern will be
         validated. If None, all docstrings will be validated.
+    ignore_deprecated: bool, default False
+        If True, deprecated objects are ignored when validating docstrings.
 
     Returns
     -------
@@ -750,6 +752,8 @@ def validate_all(prefix):
         if prefix and not func_name.startswith(prefix):
             continue
         doc_info = validate_one(func_name)
+        if ignore_deprecated and doc_info['deprecated']:
+            continue
         result[func_name] = doc_info
 
         shared_code_key = doc_info['file'], doc_info['file_line']
@@ -771,13 +775,15 @@ def validate_all(prefix):
                 if prefix and not func_name.startswith(prefix):
                     continue
                 doc_info = validate_one(func_name)
+                if ignore_deprecated and doc_info['deprecated']:
+                    continue
                 result[func_name] = doc_info
                 result[func_name]['in_api'] = False
 
     return result
 
 
-def main(func_name, prefix, errors, output_format):
+def main(func_name, prefix, errors, output_format, ignore_deprecated):
     def header(title, width=80, char='#'):
         full_line = char * width
         side_len = (width - len(title) - 2) // 2
@@ -791,7 +797,7 @@ def header(title, width=80, char='#'):
 
     exit_status = 0
     if func_name is None:
-        result = validate_all(prefix)
+        result = validate_all(prefix, ignore_deprecated)
 
         if output_format == 'json':
             output = json.dumps(result)
@@ -882,8 +888,13 @@ def header(title, width=80, char='#'):
                            'list of error codes to validate. By default it '
                            'validates all errors (ignored when validating '
                            'a single docstring)')
+    argparser.add_argument('--ignore_deprecated', default=False,
+                           action='store_true', help='if this flag is set, '
+                           'deprecated objects are ignored when validating '
+                           'all docstrings')
 
     args = argparser.parse_args()
     sys.exit(main(args.function, args.prefix,
                   args.errors.split(',') if args.errors else None,
-                  args.format))
+                  args.format,
+                  args.ignore_deprecated))


Test patch:
diff --git a/scripts/tests/test_validate_docstrings.py b/scripts/tests/test_validate_docstrings.py
--- a/scripts/tests/test_validate_docstrings.py
+++ b/scripts/tests/test_validate_docstrings.py
@@ -817,6 +817,20 @@ def test_bad_examples(self, capsys, klass, func, msgs):
         for msg in msgs:
             assert msg in ' '.join(err[1] for err in result['errors'])
 
+    def test_validate_all_ignore_deprecated(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': '',
+                'deprecated': True})
+        result = validate_docstrings.validate_all(prefix=None,
+                                                  ignore_deprecated=True)
+        assert len(result) == 0
+
 
 class TestApiItems(object):
     @property
@@ -907,12 +921,14 @@ def test_exit_status_for_validate_one(self, monkeypatch):
         exit_status = validate_docstrings.main(func_name='docstring1',
                                                prefix=None,
                                                errors=[],
-                                               output_format='default')
+                                               output_format='default',
+                                               ignore_deprecated=False)
         assert exit_status == 0
 
     def test_exit_status_errors_for_validate_all(self, monkeypatch):
         monkeypatch.setattr(
-            validate_docstrings, 'validate_all', lambda prefix: {
+            validate_docstrings, 'validate_all',
+            lambda prefix, ignore_deprecated=False: {
                 'docstring1': {'errors': [('ER01', 'err desc'),
                                           ('ER02', 'err desc'),
                                           ('ER03', 'err desc')],
@@ -925,25 +941,29 @@ def test_exit_status_errors_for_validate_all(self, monkeypatch):
         exit_status = validate_docstrings.main(func_name=None,
                                                prefix=None,
                                                errors=[],
-                                               output_format='default')
+                                               output_format='default',
+                                               ignore_deprecated=False)
         assert exit_status == 5
 
     def test_no_exit_status_noerrors_for_validate_all(self, monkeypatch):
         monkeypatch.setattr(
-            validate_docstrings, 'validate_all', lambda prefix: {
+            validate_docstrings, 'validate_all',
+            lambda prefix, ignore_deprecated=False: {
                 'docstring1': {'errors': [],
                                'warnings': [('WN01', 'warn desc')]},
                 'docstring2': {'errors': []}})
         exit_status = validate_docstrings.main(func_name=None,
                                                prefix=None,
                                                errors=[],
-                                               output_format='default')
+                                               output_format='default',
+                                               ignore_deprecated=False)
         assert exit_status == 0
 
     def test_exit_status_for_validate_all_json(self, monkeypatch):
         print('EXECUTED')
         monkeypatch.setattr(
-            validate_docstrings, 'validate_all', lambda prefix: {
+            validate_docstrings, 'validate_all',
+            lambda prefix, ignore_deprecated=False: {
                 'docstring1': {'errors': [('ER01', 'err desc'),
                                           ('ER02', 'err desc'),
                                           ('ER03', 'err desc')]},
@@ -952,12 +972,14 @@ def test_exit_status_for_validate_all_json(self, monkeypatch):
         exit_status = validate_docstrings.main(func_name=None,
                                                prefix=None,
                                                errors=[],
-                                               output_format='json')
+                                               output_format='json',
+                                               ignore_deprecated=False)
         assert exit_status == 0
 
     def test_errors_param_filters_errors(self, monkeypatch):
         monkeypatch.setattr(
-            validate_docstrings, 'validate_all', lambda prefix: {
+            validate_docstrings, 'validate_all',
+            lambda prefix, ignore_deprecated=False: {
                 'Series.foo': {'errors': [('ER01', 'err desc'),
                                           ('ER02', 'err desc'),
                                           ('ER03', 'err desc')],
@@ -973,11 +995,13 @@ def test_errors_param_filters_errors(self, monkeypatch):
         exit_status = validate_docstrings.main(func_name=None,
                                                prefix=None,
                                                errors=['ER01'],
-                                               output_format='default')
+                                               output_format='default',
+                                               ignore_deprecated=False)
         assert exit_status == 3
 
         exit_status = validate_docstrings.main(func_name=None,
                                                prefix=None,
                                                errors=['ER03'],
-                                               output_format='default')
+                                               output_format='default',
+                                               ignore_deprecated=False)
         assert exit_status == 1