diff --git a/scripts/validate_docstrings.py b/scripts/validate_docstrings.py index 1c45c79ba7fba..43a1e5b3b4478 100755 --- a/scripts/validate_docstrings.py +++ b/scripts/validate_docstrings.py @@ -26,6 +26,8 @@ import importlib import doctest import tempfile +import configparser +import itertools import ast import textwrap @@ -156,6 +158,19 @@ def error(code, **kwargs): return (code, ERROR_MSGS[code].format(**kwargs)) +def get_setupcfg(): + """ + Returns a ConfigParser which reads the setup.cfg file in the root + directory. + """ + setup_cfg = os.path.join(BASE_PATH, 'setup.cfg') + config = configparser.ConfigParser(inline_comment_prefixes='#') + config.optionxform = str + with open(setup_cfg, 'r') as file: + config.read_file(file) + return config + + def get_api_items(api_doc_fd): """ Yield information about all public API items. @@ -811,7 +826,7 @@ def validate_one(func_name): 'examples_errors': examples_errs} -def validate_all(prefix, ignore_deprecated=False): +def validate_all(prefix, ignore_deprecated=False, ignore_known_fail=False): """ Execute the validation of all docstrings, and return a dict with the results. @@ -832,6 +847,9 @@ def validate_all(prefix, ignore_deprecated=False): """ result = {} seen = {} + if ignore_known_fail: + config = get_setupcfg() + known_fails = dict(config.items('known_fail')) # functions from the API docs api_doc_fnames = os.path.join( @@ -846,6 +864,12 @@ def validate_all(prefix, ignore_deprecated=False): doc_info = validate_one(func_name) if ignore_deprecated and doc_info['deprecated']: continue + if ignore_known_fail and func_name in known_fails: + doc_info['errors'] = list(itertools.filterfalse( + lambda x: x[0] in known_fails[func_name].split(','), + doc_info['errors'])) + if not doc_info['errors']: + continue result[func_name] = doc_info shared_code_key = doc_info['file'], doc_info['file_line'] @@ -869,13 +893,20 @@ def validate_all(prefix, ignore_deprecated=False): doc_info = validate_one(func_name) if ignore_deprecated and doc_info['deprecated']: continue + if ignore_known_fail and func_name in known_fails: + doc_info['errors'] = list(itertools.filterfalse( + lambda x: x[0] in known_fails[func_name].split(','), + doc_info['errors'])) + if not doc_info['errors']: + continue result[func_name] = doc_info result[func_name]['in_api'] = False return result -def main(func_name, prefix, errors, output_format, ignore_deprecated): +def main(func_name, prefix, errors, output_format, ignore_deprecated, + ignore_known_fail): def header(title, width=80, char='#'): full_line = char * width side_len = (width - len(title) - 2) // 2 @@ -889,7 +920,7 @@ def header(title, width=80, char='#'): exit_status = 0 if func_name is None: - result = validate_all(prefix, ignore_deprecated) + result = validate_all(prefix, ignore_deprecated, ignore_known_fail) if output_format == 'json': output = json.dumps(result) @@ -984,9 +1015,14 @@ def header(title, width=80, char='#'): action='store_true', help='if this flag is set, ' 'deprecated objects are ignored when validating ' 'all docstrings') + argparser.add_argument('--ignore_known_fail', default=False, + action='store_true', help='if this flag is set, ' + 'objects listed in setup.cfg as known_fail 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.ignore_deprecated)) + args.ignore_deprecated, + args.ignore_known_fail)) diff --git a/setup.cfg b/setup.cfg index 84b8f69a83f16..9ac5405c1ae3e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -173,3 +173,26 @@ skip= pandas/_libs/tslibs/__init__.py pandas/util/__init__.py pandas/arrays/__init__.py + +[scripts:validate_docstrings] + [known_fail] + # function_name = comma separated error_codes commented reason for ignoring + pandas.Timestamp.ctime = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.date = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.dst = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.isocalendar = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.isoweekday = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.strftime = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.strptime = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.time = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.timestamp = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.timetuple = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.timetz = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.toordinal = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.tzname = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.utcoffset = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.utctimetuple = GL01,GL02 # inherits from cpython datetime library + pandas.Timestamp.weekday = GL01,GL02 # inherits from cpython datetime library + pandas.Timedelta.days = GL01,GL02 # inherits from cpython datetime library + pandas.Timedelta.microseconds = GL01,GL02 # inherits from cpython datetime library + pandas.Timedelta.seconds = GL01,GL02 # inherits from cpython datetime library