Skip to content

Commit

Permalink
FIX-modin-project#7240: Allow 'doc_checker.py' works with 'functools.…
Browse files Browse the repository at this point in the history
…cached_property'

Signed-off-by: Anatoly Myachev <[email protected]>
  • Loading branch information
anmyachev committed May 7, 2024
1 parent f8bf5b4 commit c55855a
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 50 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-required.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ jobs:
- uses: actions/checkout@v4
- uses: ./.github/actions/python-only
# The `numpydoc` version here MUST match the versions in the dev requirements files.
- run: pip install pytest pytest-cov pydocstyle numpydoc==1.1.0
- run: pip install pytest pytest-cov pydocstyle numpydoc==1.6.0
- run: python -m pytest scripts/test
- run: pip install -e ".[all]"
- run: |
Expand Down
2 changes: 1 addition & 1 deletion environment-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ dependencies:
# Fixes breaking ipywidgets changes, but didn't release yet.
- git+https://github.com/modin-project/modin-spreadsheet.git@49ffd89f683f54c311867d602c55443fb11bf2a5
# The `numpydoc` version should match the version installed in the `lint-pydocstyle` job of the CI.
- numpydoc==1.1.0
- numpydoc==1.6.0
2 changes: 1 addition & 1 deletion requirements/env_hdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ dependencies:
- pip:
- dataframe-api-compat>=0.2.7
# The `numpydoc` version should match the version installed in the `lint-pydocstyle` job of the CI.
- numpydoc==1.1.0
- numpydoc==1.6.0
2 changes: 1 addition & 1 deletion requirements/env_unidist_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ dependencies:
- git+https://github.com/modin-project/modin-spreadsheet.git@49ffd89f683f54c311867d602c55443fb11bf2a5
- connectorx>=0.2.6a4
# The `numpydoc` version should match the version installed in the `lint-pydocstyle` job of the CI.
- numpydoc==1.1.0
- numpydoc==1.6.0
2 changes: 1 addition & 1 deletion requirements/env_unidist_win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ dependencies:
- git+https://github.com/modin-project/modin-spreadsheet.git@49ffd89f683f54c311867d602c55443fb11bf2a5
- connectorx>=0.2.6a4
# The `numpydoc` version should match the version installed in the `lint-pydocstyle` job of the CI.
- numpydoc==1.1.0
- numpydoc==1.6.0
2 changes: 1 addition & 1 deletion requirements/requirements-no-engine.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,4 @@ dependencies:
# Fixes breaking ipywidgets changes, but didn't release yet.
- git+https://github.com/modin-project/modin-spreadsheet.git@49ffd89f683f54c311867d602c55443fb11bf2a5
# The `numpydoc` version should match the version installed in the `lint-pydocstyle` job of the CI.
- numpydoc==1.1.0
- numpydoc==1.6.0
92 changes: 53 additions & 39 deletions scripts/doc_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@
import types
from typing import List

from numpydoc.docscrape import NumpyDocString
from numpydoc.validate import Docstring
from numpydoc.docscrape import NumpyDocString, get_doc_object
from numpydoc.validate import Validator

# Let the other modules to know that the doc checker is running.
os.environ["_MODIN_DOC_CHECKER_"] = "1"
Expand Down Expand Up @@ -73,14 +73,14 @@
}


def get_optional_args(doc: Docstring) -> dict:
def get_optional_args(doc: Validator) -> dict:
"""
Get optional parameters for the object for which the docstring is checked.
Parameters
----------
doc : numpydoc.validate.Docstring
Docstring handler.
doc : numpydoc.validate.Validator
Validator handler.
Returns
-------
Expand All @@ -98,13 +98,13 @@ def get_optional_args(doc: Docstring) -> dict:
}


def check_optional_args(doc: Docstring) -> list:
def check_optional_args(doc: Validator) -> list:
"""
Check type description of optional arguments.
Parameters
----------
doc : numpydoc.validate.Docstring
doc : numpydoc.validate.Validator
Returns
-------
Expand Down Expand Up @@ -139,14 +139,14 @@ def check_optional_args(doc: Docstring) -> list:
return errors


def check_spelling_words(doc: Docstring) -> list:
def check_spelling_words(doc: Validator) -> list:
"""
Check spelling of chosen words in doc.
Parameters
----------
doc : numpydoc.validate.Docstring
Docstring handler.
doc : numpydoc.validate.Validator
Validator handler.
Returns
-------
Expand Down Expand Up @@ -188,9 +188,18 @@ def check_spelling_words(doc: Docstring) -> list:
]

docstring_start_line = None
for idx, line in enumerate(inspect.getsourcelines(doc.code_obj)[0]):
code_obj = doc.code_obj
if isinstance(code_obj, property):
# inspect.getsourcelines doesn't work with property
code_obj = code_obj.fget
elif isinstance(code_obj, functools.cached_property):
# inspect.getsourcelines doesn't work with cached_property
code_obj = code_obj.func

rows, starting_line = inspect.getsourcelines(code_obj)
for idx, line in enumerate(rows):
if '"""' in line or "'''" in line:
docstring_start_line = doc.source_file_def_line + idx
docstring_start_line = starting_line + idx
break

errors = []
Expand All @@ -210,14 +219,14 @@ def check_spelling_words(doc: Docstring) -> list:
return errors


def check_docstring_indention(doc: Docstring) -> list:
def check_docstring_indention(doc: Validator) -> list:
"""
Check indention of docstring since numpydoc reports weird results.
Parameters
----------
doc : numpydoc.validate.Docstring
Docstring handler.
doc : numpydoc.validate.Validator
Validator handler.
Returns
-------
Expand All @@ -240,14 +249,14 @@ def check_docstring_indention(doc: Docstring) -> list:
return errors


def validate_modin_error(doc: Docstring, results: dict) -> list:
def validate_modin_error(doc: Validator, results: dict) -> list:
"""
Validate custom Modin errors.
Parameters
----------
doc : numpydoc.validate.Docstring
Docstring handler.
doc : numpydoc.validate.Validator
Validator handler.
results : dict
Dictionary that numpydoc.validate.validate return.
Expand All @@ -263,14 +272,14 @@ def validate_modin_error(doc: Docstring, results: dict) -> list:
return results


def skip_check_if_noqa(doc: Docstring, err_code: str, noqa_checks: list) -> bool:
def skip_check_if_noqa(doc: Validator, err_code: str, noqa_checks: list) -> bool:
"""
Skip the check that matches `err_code` if `err_code` found in noqa string.
Parameters
----------
doc : numpydoc.validate.Docstring
Docstring handler.
doc : numpydoc.validate.Validator
Validator handler.
err_code : str
Error code found by numpydoc.
noqa_checks : list
Expand All @@ -286,22 +295,31 @@ def skip_check_if_noqa(doc: Docstring, err_code: str, noqa_checks: list) -> bool

# GL08 - missing docstring in an arbitary object; numpydoc code
if err_code == "GL08":
name = doc.name.split(".")[-1]
# Numpydoc recommends to add docstrings of __init__ method in class docstring.
# So there is no error if docstring is missing in __init__
if name == "__init__":
return True
try:
name = doc.name.split(".")[-1]
# Numpydoc recommends to add docstrings of __init__ method in class docstring.
# So there is no error if docstring is missing in __init__
if name == "__init__":
return True
except AttributeError as exc:
# Cashed properties are not used for constructors, so we can safely ignore this exception
if (
not len(exc.args) > 0
and exc.args[0]
== "'cached_property' object has no attribute '__name__'"
):
raise exc
return err_code in noqa_checks


def get_noqa_checks(doc: Docstring) -> list:
def get_noqa_checks(doc: Validator) -> list:
"""
Get codes after `# noqa`.
Parameters
----------
doc : numpydoc.validate.Docstring
Docstring handler.
doc : numpydoc.validate.Validator
Validator handler.
Returns
-------
Expand Down Expand Up @@ -343,6 +361,11 @@ def get_noqa_checks(doc: Docstring) -> list:
return [check.strip() for check in noqa_checks]


def construct_validator(import_path: str) -> Validator: # GL08
# helper function
return Validator(get_doc_object(Validator._load_obj(import_path)))


# code snippet from numpydoc
def validate_object(import_path: str) -> list:
"""
Expand All @@ -361,7 +384,7 @@ def validate_object(import_path: str) -> list:
from numpydoc.validate import validate

errors = []
doc = Docstring(import_path)
doc = construct_validator(import_path)
if getattr(doc.obj, "__doc_inherited__", False) or (
isinstance(doc.obj, property)
and getattr(doc.obj.fget, "__doc_inherited__", False)
Expand Down Expand Up @@ -521,15 +544,6 @@ def monkeypatch(*args, **kwargs):

modin.utils.instancer = functools.wraps(modin.utils.instancer)(lambda cls: cls)

# monkey-patch numpydoc for working correctly with properties
def load_obj(name, old_load_obj=Docstring._load_obj):
obj = old_load_obj(name)
if isinstance(obj, property):
obj = obj.fget
return obj

Docstring._load_obj = staticmethod(load_obj)

# for testing hdk-engine docs without `pyhdk` installation
sys.modules["pyhdk"] = Mock()
sys.modules["pyhdk"].__version__ = "999"
Expand Down
10 changes: 5 additions & 5 deletions scripts/test/test_doc_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
# governing permissions and limitations under the License.

import pytest
from numpydoc.validate import Docstring

from scripts.doc_checker import (
MODIN_ERROR_CODES,
check_optional_args,
check_spelling_words,
construct_validator,
get_noqa_checks,
get_optional_args,
)
Expand All @@ -34,7 +34,7 @@
],
)
def test_get_optional_args(import_path, result):
optional_args = get_optional_args(Docstring(import_path))
optional_args = get_optional_args(construct_validator(import_path))
assert optional_args == result


Expand All @@ -57,7 +57,7 @@ def test_get_optional_args(import_path, result):
],
)
def test_check_optional_args(import_path, result):
errors = check_optional_args(Docstring(import_path))
errors = check_optional_args(construct_validator(import_path))
assert errors == result


Expand Down Expand Up @@ -88,7 +88,7 @@ def test_check_spelling_words(import_path, result):
),
)
)
errors = check_spelling_words(Docstring(import_path))
errors = check_spelling_words(construct_validator(import_path))
# the order of incorrect words found on the same line is not guaranteed
for error in errors:
assert error in result_errors
Expand All @@ -105,5 +105,5 @@ def test_check_spelling_words(import_path, result):
],
)
def test_get_noqa_checks(import_path, result):
noqa_checks = get_noqa_checks(Docstring(import_path))
noqa_checks = get_noqa_checks(construct_validator(import_path))
assert noqa_checks == result

0 comments on commit c55855a

Please sign in to comment.