From cc739fb583e272788953484828103b36996d7b96 Mon Sep 17 00:00:00 2001 From: sishubha Date: Tue, 5 Apr 2022 13:00:55 +0530 Subject: [PATCH 1/4] Fix Stubgen's behavior for Instance Variables in C extensions It is not necessary for instance variables to have the fget attrbute (e.g. instance variable in a C class in an extension) but inspect.isdatadescriptor return True as expected, hence we update the 'is_c_property' check. Since special attributes (like __dict__ etc) also passes 'is_c_property' check, we ignore all such special attributes in 'generate_c_property_stub' while creating the contents of stub file. Also, 'is_c_property_readonly' assumed that the property would always have 'fset' attribute which again is not true for instance variables in C extension. Hence make the check defensive by first checking if 'fset' attribute even exists or not. This fixes #12150. --- mypy/stubgenc.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mypy/stubgenc.py b/mypy/stubgenc.py index 0eeb39f102dc..4b0bd4a62552 100755 --- a/mypy/stubgenc.py +++ b/mypy/stubgenc.py @@ -121,11 +121,11 @@ def is_c_classmethod(obj: object) -> bool: def is_c_property(obj: object) -> bool: - return inspect.isdatadescriptor(obj) and hasattr(obj, 'fget') + return inspect.isdatadescriptor(obj) or hasattr(obj, 'fget') def is_c_property_readonly(prop: Any) -> bool: - return prop.fset is None + return hasattr(prop, 'fset') and prop.fset is None def is_c_type(obj: object) -> bool: @@ -287,6 +287,10 @@ def infer_prop_type(docstr: Optional[str]) -> Optional[str]: else: return None + # Ignore special properties/attributes. + if name.startswith('__') and name.endswith('__'): + return + inferred = infer_prop_type(getattr(obj, '__doc__', None)) if not inferred: fget = getattr(obj, 'fget', None) From 245211c412a32e34bba5744c99d6b3763f285b17 Mon Sep 17 00:00:00 2001 From: sishubha Date: Wed, 6 Apr 2022 13:42:02 +0530 Subject: [PATCH 2/4] Update stubgen test files --- test-data/stubgen/pybind11_mypy_demo/basics.pyi | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test-data/stubgen/pybind11_mypy_demo/basics.pyi b/test-data/stubgen/pybind11_mypy_demo/basics.pyi index 7c83f4ad2256..99093fd6087a 100644 --- a/test-data/stubgen/pybind11_mypy_demo/basics.pyi +++ b/test-data/stubgen/pybind11_mypy_demo/basics.pyi @@ -5,8 +5,6 @@ PI: float class Point: class AngleUnit: - __doc__: ClassVar[str] = ... # read-only - __members__: ClassVar[dict] = ... # read-only __entries: ClassVar[dict] = ... degree: ClassVar[Point.AngleUnit] = ... radian: ClassVar[Point.AngleUnit] = ... @@ -22,8 +20,6 @@ class Point: def name(self) -> str: ... class LengthUnit: - __doc__: ClassVar[str] = ... # read-only - __members__: ClassVar[dict] = ... # read-only __entries: ClassVar[dict] = ... inch: ClassVar[Point.LengthUnit] = ... mm: ClassVar[Point.LengthUnit] = ... From 1a77ea94a696285f3b6ea6c4e607ab96a698b255 Mon Sep 17 00:00:00 2001 From: sishubha Date: Thu, 7 Apr 2022 21:00:15 +0530 Subject: [PATCH 3/4] Add test cases --- mypy/test/teststubgen.py | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/mypy/test/teststubgen.py b/mypy/test/teststubgen.py index c999e3c82643..737a291a30e3 100644 --- a/mypy/test/teststubgen.py +++ b/mypy/test/teststubgen.py @@ -20,7 +20,8 @@ ) from mypy.stubutil import walk_packages, remove_misplaced_type_comments, common_dir_prefix from mypy.stubgenc import ( - generate_c_type_stub, infer_method_sig, generate_c_function_stub, generate_c_property_stub + generate_c_type_stub, infer_method_sig, generate_c_function_stub, generate_c_property_stub, + is_c_property_readonly ) from mypy.stubdoc import ( parse_signature, parse_all_signatures, build_signature, find_unique_signatures, @@ -868,9 +869,34 @@ def get_attribute(self) -> None: pass attribute = property(get_attribute, doc="") - output: List[str] = [] - generate_c_property_stub('attribute', TestClass.attribute, [], [], output, readonly=True) - assert_equal(output, ['@property', 'def attribute(self) -> str: ...']) + readwrite_properties: List[str] = [] + readonly_properties: List[str] = [] + generate_c_property_stub('attribute', TestClass.attribute, [], + readwrite_properties, readonly_properties, + is_c_property_readonly(type(TestClass.attribute))) + assert_equal(readwrite_properties, []) + assert_equal(readonly_properties, ['@property', 'def attribute(self) -> str: ...']) + + def test_generate_c_property_with_rw_property(self) -> None: + class TestClass: + def __init__(self) -> None: + self._attribute = 0 + + @property + def attribute(self) -> int: + return self._attribute + + @attribute.setter + def attribute(self, value: int) -> None: + self._attribute = value + + readwrite_properties: List[str] = [] + readonly_properties: List[str] = [] + generate_c_property_stub("attribute", type(TestClass.attribute), [], + readwrite_properties, readonly_properties, + is_c_property_readonly(type(TestClass.attribute))) + assert_equal(readwrite_properties, ['attribute: Any']) + assert_equal(readonly_properties, []) def test_generate_c_type_with_single_arg_generic(self) -> None: class TestClass: From 34a2cdfbe571f0a7008e26aec43750d592415350 Mon Sep 17 00:00:00 2001 From: sishubha Date: Mon, 11 Apr 2022 11:53:37 +0530 Subject: [PATCH 4/4] Fix test case --- mypy/test/teststubgen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mypy/test/teststubgen.py b/mypy/test/teststubgen.py index 737a291a30e3..625ec3f30685 100644 --- a/mypy/test/teststubgen.py +++ b/mypy/test/teststubgen.py @@ -873,7 +873,7 @@ def get_attribute(self) -> None: readonly_properties: List[str] = [] generate_c_property_stub('attribute', TestClass.attribute, [], readwrite_properties, readonly_properties, - is_c_property_readonly(type(TestClass.attribute))) + is_c_property_readonly(TestClass.attribute)) assert_equal(readwrite_properties, []) assert_equal(readonly_properties, ['@property', 'def attribute(self) -> str: ...']) @@ -894,7 +894,7 @@ def attribute(self, value: int) -> None: readonly_properties: List[str] = [] generate_c_property_stub("attribute", type(TestClass.attribute), [], readwrite_properties, readonly_properties, - is_c_property_readonly(type(TestClass.attribute))) + is_c_property_readonly(TestClass.attribute)) assert_equal(readwrite_properties, ['attribute: Any']) assert_equal(readonly_properties, [])