Exemple #1
0
def validate_object(import_path):
    exit_status = 0
    results = validate(import_path)
    for err_code, err_desc in results["errors"]:
        exit_status += 1
        print(":".join([import_path, err_code, err_desc]))
    return exit_status
Exemple #2
0
def _valid_obj(full_import_path, obj, verbose):
    if verbose:
        v = "# -- " + full_import_path + " "
        v += "-" * (80 - len(v))
        print(v)

    try:
        _ = inspect.signature(obj)
    except ValueError:
        sys.stderr.write(full_import_path)
        sys.stderr.write(": can't get signature\n")
        return 1

    errs = validate(full_import_path)["errors"]
    if not errs:
        return 0

    exit_code = 0
    for code, msg in errs:
        if code in IGNORE:
            continue
        output = "%s:%s:%s" % (full_import_path, code, msg)
        sys.stderr.write("\n\t".join(textwrap.wrap(output, 79)))
        sys.stderr.write("\n")
        exit_code = 1
    return exit_code
Exemple #3
0
def validate_object(import_path: str) -> list:
    """
    Check docstrings of an entity that can be imported.

    Parameters
    ----------
    import_path : str
        Python-like import path.

    Returns
    -------
    errors : list
        List with string representations of errors.
    """
    from numpydoc.validate import validate

    errors = []
    doc = Docstring(import_path)
    results = validate(import_path)
    results = validate_modin_error(doc, results)
    noqa_checks = get_noqa_checks(doc)
    for err_code, err_desc in results["errors"]:
        if (err_code not in NUMPYDOC_BASE_ERROR_CODES
                and err_code not in MODIN_ERROR_CODES) or skip_check_if_noqa(
                    doc, err_code, noqa_checks):
            continue
        errors.append(":".join(
            [import_path,
             str(results["file_line"]), err_code, err_desc]))
    return errors
Exemple #4
0
def pandas_validate(func_name: str):
    """
    Call the numpydoc validation, and add the errors specific to pandas.

    Parameters
    ----------
    func_name : str
        Name of the object of the docstring to validate.

    Returns
    -------
    dict
        Information about the docstring and the errors found.
    """
    doc = PandasDocstring(func_name)
    result = validate(func_name)

    mentioned_errs = doc.mentioned_private_classes
    if mentioned_errs:
        result["errors"].append(
            pandas_error("GL04",
                         mentioned_private_classes=", ".join(mentioned_errs)))

    if doc.see_also:
        for rel_name in doc.see_also:
            if rel_name.startswith("pandas."):
                result["errors"].append(
                    pandas_error(
                        "SA05",
                        reference_name=rel_name,
                        right_reference=rel_name[len("pandas."):],
                    ))

    result["examples_errs"] = ""
    if doc.examples:
        result["examples_errs"] = doc.examples_errors
        if result["examples_errs"]:
            result["errors"].append(
                pandas_error("EX02", doctest_log=result["examples_errs"]))

        for error_code, error_message, error_count in doc.validate_pep8():
            times_happening = f" ({error_count} times)" if error_count > 1 else ""
            result["errors"].append(
                pandas_error(
                    "EX03",
                    error_code=error_code,
                    error_message=error_message,
                    times_happening=times_happening,
                ))
        examples_source_code = "".join(doc.examples_source_code)
        for wrong_import in ("numpy", "pandas"):
            if f"import {wrong_import}" in examples_source_code:
                result["errors"].append(
                    pandas_error("EX04", imported_library=wrong_import))

    if doc.non_hyphenated_array_like():
        result["errors"].append(pandas_error("GL05"))

    plt.close("all")
    return result
Exemple #5
0
        def callback(obj):
            result = validate(obj)

            errors = []
            for errcode, errmsg in result.get('errors', []):
                if allow_rules and errcode not in allow_rules:
                    continue
                if disallow_rules and errcode in disallow_rules:
                    continue
                errors.append((errcode, errmsg))

            if len(errors):
                result['errors'] = errors
                results.append((obj, result))
Exemple #6
0
        def callback(obj):
            result = validate(obj)

            errors = []
            for errcode, errmsg in result.get('errors', []):
                if rules_whitelist and errcode not in rules_whitelist:
                    continue
                if rules_blacklist and errcode in rules_blacklist:
                    continue
                errors.append((errcode, errmsg))

            if len(errors):
                result['errors'] = errors
                results.append((obj, result))
def check_parameters_match(func):
    """Check docstring, return list of incorrect results."""
    from numpydoc.validate import validate
    name = _func_name(func)
    skip = (not name.startswith('mne.') or
            any(re.match(d, name) for d in docstring_ignores) or
            'deprecation_wrapped' in getattr(
                getattr(func, '__code__', None), 'co_name', ''))
    if skip:
        return list()
    incorrect = ['%s : %s : %s' % (name, err[0], err[1])
                 for err in validate(name)['errors']
                 if err[0] not in error_ignores]
    return incorrect
Exemple #8
0
def check_parameters_match(func, cls=None):
    """Check docstring, return list of incorrect results."""
    from numpydoc.validate import validate
    name = _func_name(func, cls)
    skip = (not name.startswith('mne.') or
            any(re.match(d, name) for d in docstring_ignores))
    if skip:
        return list()
    if cls is not None:
        for subclass, ignores in subclass_name_ignores:
            if issubclass(cls, subclass) and name.split('.')[-1] in ignores:
                return list()
    incorrect = ['%s : %s : %s' % (name, err[0], err[1])
                 for err in validate(name)['errors']
                 if err[0] not in error_ignores and
                 (name.split('.')[-1], err[0]) not in error_ignores_specific]
    return incorrect
Exemple #9
0
        def callback(obj):
            try:
                result = validate(obj)
            except OSError as e:
                symbol = f"{obj.__module__}.{obj.__name__}"
                logger.warning(f"Unable to validate `{symbol}` due to `{e}`")
                return

            errors = []
            for errcode, errmsg in result.get('errors', []):
                if allow_rules and errcode not in allow_rules:
                    continue
                if disallow_rules and errcode in disallow_rules:
                    continue
                errors.append((errcode, errmsg))

            if len(errors):
                result['errors'] = errors
                results.append((obj, result))
Exemple #10
0
    def test_docstrings(self):
        failures = {}
        # Loop over directories
        for dirpath in sorted(directories):

            # Loop over files
            for file_name in sorted(os.listdir(dirpath)):
                if not file_name.startswith("_") and file_name[-3:] == '.py' \
                   and not os.path.isdir(file_name):

                    # To construct module name, remove part of abs path that
                    # precedes 'openmdao', and then replace '/' with '.' in the remainder.
                    mod1 = re.sub(r'.*openmdao', 'openmdao',
                                  dirpath).replace('/', '.')

                    # Then, get rid of the '.py' to get final part of module name.
                    mod2 = file_name[:-3]

                    module_name = f'{mod1}.{mod2}'

                    try:
                        mod = importlib.import_module(module_name)
                    except ImportError as err:
                        print('Skipped:', err)
                        # e.g. PETSc is not installed
                        continue

                    classes = [
                        x for x in dir(mod) if not x.startswith('_')
                        and inspect.isclass(getattr(mod, x))
                        and getattr(mod, x).__module__ == module_name
                    ]

                    # Loop over classes.
                    for class_name in classes:
                        full_class_path = f'{module_name}.{class_name}'
                        try:
                            result = validate.validate(full_class_path)
                        except:
                            continue

                        failures.update(
                            self._failure_dict(full_class_path, result))

                        clss = getattr(mod, class_name)

                        methods = [
                            x for x in dir(clss)
                            if (inspect.ismethod(getattr(clss, x))
                                or inspect.isfunction(getattr(clss, x)))
                            and x in clss.__dict__
                        ]

                        # Loop over class methods.
                        for method_name in methods:

                            if not method_name.startswith('_'):
                                full_method_path = f'{module_name}.{class_name}.{method_name}'
                                try:
                                    result = validate.validate(
                                        full_method_path)
                                except:
                                    continue

                                failures.update(
                                    self._failure_dict(full_method_path,
                                                       result))

                    tree = ast.parse(inspect.getsource(mod))

                    if hasattr(tree, 'body'):
                        funcs = [
                            node.name for node in tree.body
                            if isinstance(node, ast.FunctionDef)
                        ]
                    else:
                        funcs = []

                    # Loop over standalone functions.
                    for func_name in funcs:
                        if not func_name.startswith('_'):
                            full_function_path = f'{module_name}.{func_name}'
                            try:
                                result = validate.validate(full_function_path)
                            except:
                                continue

                            failures.update(
                                self._failure_dict(full_function_path, result))

        if failures:
            msg = '\n'
            count = 0
            for key in failures:
                msg += f'{key}\n'
                count += len(failures[key])
                for failure in failures[key]:
                    msg += f'    {failure}\n'
            msg += f'Found {count} issues in docstrings'
            self.fail(msg)
Exemple #11
0
def spectrochempy_validate(func_name, exclude=[]):
    """
    Call the numpydoc validation, and add the errors specific to spectrochempy.

    Parameters
    ----------
    func_name : str
        Name of the object of the docstring to validate.
    exclude : list
        List of error code to exclude, e.g. ["SA01", ...].

    Returns
    -------
    dict
        Information about the docstring and the errors found.
    """
    func_obj = Validator._load_obj(func_name)
    doc_obj = get_doc_object(func_obj)
    doc = SpectroChemPyDocstring(func_name, doc_obj)
    result = validate(doc_obj)
    errs = result["errors"]

    mentioned_errs = doc.mentioned_private_classes
    if mentioned_errs:
        errs.append(
            spectrochempy_error(
                "GL04", mentioned_private_classes=", ".join(mentioned_errs)))

    has_kwargs = doc.has_kwargs
    if has_kwargs:
        errs = remove_errors(errs, "PR02")
        if not doc.doc_other_parameters:
            errs.append(spectrochempy_error("GL11"))

    if exclude:
        errs = remove_errors(errs, exclude)

    if doc.see_also:
        for rel_name in doc.see_also:
            if rel_name.startswith("spectrochempy."):
                errs.append(
                    spectrochempy_error(
                        "SA05",
                        reference_name=rel_name,
                        right_reference=rel_name[len("spectrochempy."):],
                    ))

    result["examples_errs"] = ""
    if doc.examples:
        result["examples_errs"] = doc.examples_errors
        if result["examples_errs"]:
            errs.append(
                spectrochempy_error("EX02",
                                    doctest_log=result["examples_errs"]))

        for error_code, error_message, error_count in doc.validate_pep8():
            times_happening = f" ({error_count} times)" if error_count > 1 else ""
            errs.append(
                spectrochempy_error(
                    "EX03",
                    error_code=error_code,
                    error_message=error_message,
                    times_happening=times_happening,
                ))
        examples_source_code = "".join(doc.examples_source_code)
        for wrong_import in ("numpy", "spectrochempy"):
            if f"import {wrong_import}" in examples_source_code:
                errs.append(
                    spectrochempy_error("EX04", imported_library=wrong_import))

    if doc.non_hyphenated_array_like():
        errs.append(spectrochempy_error("GL05"))

    # cases where docrep dedent was used
    if error("GL01") in errs and not doc.raw_doc.startswith(""):
        errs = remove_errors(errs, "GL01")
    if error("GL02") in errs and not doc.raw_doc.startswith(""):
        errs = remove_errors(errs, "GL02")

    # case of properties (we accept a single line summary)
    if hasattr(doc.code_obj, "fget"):
        errs = remove_errors(errs, "ES01")

    result["errors"] = errs
    plt.close("all")
    if result["file"] is None:
        # sometimes it is because the code_obj is a property
        if hasattr(doc.code_obj, "fget"):
            try:
                result["file"] = inspect.getsourcefile(doc.code_obj.fget)
                result["file_line"] = inspect.getsourcelines(
                    doc.code_obj.fget)[-1]
            except (OSError, TypeError):
                pass

    return result
Exemple #12
0
        "paths",
        nargs="+",
        type=pathlib.Path,
        help=
        "Filenames or directories; in case of direstories perform recursive check",
    )
    parser.add_argument(
        "--add-ignore",
        nargs="*",
        default=[],
        help="Pydocstyle error codes; for example: D100,D100,D102",
    )
    parser.add_argument(
        "--disable-numpydoc",
        default=False,
        action="store_true",
        help="Determine if numpydoc checks are not needed",
    )
    args = parser.parse_args()
    check_args(args)
    return args


if __name__ == "__main__":
    args = get_args()
    monkeypatching()
    if not validate(args.paths, args.add_ignore, not args.disable_numpydoc):
        logging.error("INVALID DOCUMENTATION FOUND")
        exit(1)
    logging.info("SUCCESSFUL CHECK")