Repository: modin-project/modin

Issue:
Allow `doc_checker.py` works with `functools.cached_property`



Discussion:

Resolving patch:
diff --git a/scripts/doc_checker.py b/scripts/doc_checker.py
--- a/scripts/doc_checker.py
+++ b/scripts/doc_checker.py
@@ -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"
@@ -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
     -------
@@ -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
     -------
@@ -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
     -------
@@ -210,14 +210,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
     -------
@@ -240,14 +240,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.
 
@@ -263,14 +263,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
@@ -294,14 +294,14 @@ def skip_check_if_noqa(doc: Docstring, err_code: str, noqa_checks: list) -> bool
     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
     -------
@@ -343,6 +343,11 @@ def get_noqa_checks(doc: Docstring) -> list:
     return [check.strip() for check in noqa_checks]
 
 
+def construct_validator(import_path: str) -> Validator:  # noqa: GL08
+    # helper function
+    return Validator(get_doc_object(Validator._load_obj(import_path)))
+
+
 # code snippet from numpydoc
 def validate_object(import_path: str) -> list:
     """
@@ -361,7 +366,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)
@@ -522,13 +527,16 @@ 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):
+    # until https://github.com/numpy/numpydoc/issues/551 is fixed
+    def load_obj(name, old_load_obj=Validator._load_obj):
         obj = old_load_obj(name)
         if isinstance(obj, property):
             obj = obj.fget
+        elif isinstance(obj, functools.cached_property):
+            obj = obj.func
         return obj
 
-    Docstring._load_obj = staticmethod(load_obj)
+    Validator._load_obj = staticmethod(load_obj)
 
     # for testing hdk-engine docs without `pyhdk` installation
     sys.modules["pyhdk"] = Mock()


Test patch:
diff --git a/scripts/test/test_doc_checker.py b/scripts/test/test_doc_checker.py
--- a/scripts/test/test_doc_checker.py
+++ b/scripts/test/test_doc_checker.py
@@ -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,
 )
@@ -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
 
 
@@ -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
 
 
@@ -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
@@ -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