Skip to content

Commit 422e9b7

Browse files
DanielNoordcdce8p
andauthored
Pass doc_node to postinit of all Property constructors (#1436)
Co-authored-by: Marc Mueller <[email protected]>
1 parent c21b18c commit 422e9b7

File tree

4 files changed

+79
-9
lines changed

4 files changed

+79
-9
lines changed

astroid/brain/brain_builtin_inference.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
"""Astroid hooks for various builtins."""
2424

2525
from functools import partial
26+
from typing import Optional
2627

2728
from astroid import arguments, helpers, inference_tip, nodes, objects, util
2829
from astroid.builder import AstroidBuilder
30+
from astroid.context import InferenceContext
2931
from astroid.exceptions import (
3032
AstroidTypeError,
3133
AttributeInferenceError,
@@ -548,7 +550,9 @@ def infer_callable(node, context=None):
548550
return nodes.Const(inferred.callable())
549551

550552

551-
def infer_property(node, context=None):
553+
def infer_property(
554+
node: nodes.Call, context: Optional[InferenceContext] = None
555+
) -> objects.Property:
552556
"""Understand `property` class
553557
554558
This only infers the output of `property`
@@ -570,12 +574,15 @@ def infer_property(node, context=None):
570574
prop_func = objects.Property(
571575
function=inferred,
572576
name=inferred.name,
573-
doc=getattr(inferred, "doc", None),
574577
lineno=node.lineno,
575578
parent=node,
576579
col_offset=node.col_offset,
577580
)
578-
prop_func.postinit(body=[], args=inferred.args)
581+
prop_func.postinit(
582+
body=[],
583+
args=inferred.args,
584+
doc_node=getattr(inferred, "doc_node", None),
585+
)
579586
return prop_func
580587

581588

astroid/inference.py

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,19 @@
3434
import functools
3535
import itertools
3636
import operator
37-
from typing import Any, Callable, Dict, Iterable, Iterator, Optional, Type, Union
37+
from typing import (
38+
TYPE_CHECKING,
39+
Any,
40+
Callable,
41+
Dict,
42+
Generator,
43+
Iterable,
44+
Iterator,
45+
Optional,
46+
Type,
47+
TypeVar,
48+
Union,
49+
)
3850

3951
import wrapt
4052

@@ -57,11 +69,18 @@
5769
)
5870
from astroid.interpreter import dunder_lookup
5971
from astroid.manager import AstroidManager
72+
from astroid.typing import InferenceErrorInfo
73+
74+
if TYPE_CHECKING:
75+
from astroid.objects import Property
6076

6177
# Prevents circular imports
6278
objects = util.lazy_import("objects")
6379

6480

81+
_FunctionDefT = TypeVar("_FunctionDefT", bound=nodes.FunctionDef)
82+
83+
6584
# .infer method ###############################################################
6685

6786

@@ -1063,22 +1082,23 @@ def _cached_generator(func, instance, args, kwargs, _cache={}): # noqa: B006
10631082
# are mutated with a new instance of the property. This is why we cache the result
10641083
# of the function's inference.
10651084
@_cached_generator
1066-
def infer_functiondef(self, context=None):
1085+
def infer_functiondef(
1086+
self: _FunctionDefT, context: Optional[InferenceContext] = None
1087+
) -> Generator[Union["Property", _FunctionDefT], None, InferenceErrorInfo]:
10671088
if not self.decorators or not bases._is_property(self):
10681089
yield self
1069-
return dict(node=self, context=context)
1090+
return InferenceErrorInfo(node=self, context=context)
10701091

10711092
prop_func = objects.Property(
10721093
function=self,
10731094
name=self.name,
1074-
doc=self.doc,
10751095
lineno=self.lineno,
10761096
parent=self.parent,
10771097
col_offset=self.col_offset,
10781098
)
1079-
prop_func.postinit(body=[], args=self.args)
1099+
prop_func.postinit(body=[], args=self.args, doc_node=self.doc_node)
10801100
yield prop_func
1081-
return dict(node=self, context=context)
1101+
return InferenceErrorInfo(node=self, context=context)
10821102

10831103

10841104
nodes.FunctionDef._infer = infer_functiondef # type: ignore[assignment]

astroid/typing.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html
2+
# For details: https://github.com/PyCQA/astroid/blob/main/LICENSE
3+
4+
import sys
5+
from typing import TYPE_CHECKING
6+
7+
if TYPE_CHECKING:
8+
from astroid import nodes
9+
from astroid.context import InferenceContext
10+
11+
if sys.version_info >= (3, 8):
12+
from typing import TypedDict
13+
else:
14+
from typing_extensions import TypedDict
15+
16+
17+
class InferenceErrorInfo(TypedDict):
18+
"""Store additional Inference error information
19+
raised with StopIteration exception.
20+
"""
21+
22+
node: "nodes.NodeNG"
23+
context: "InferenceContext | None"

tests/unittest_inference.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6145,6 +6145,26 @@ class A:
61456145
assert inferred.value == 42
61466146

61476147

6148+
def test_property_docstring() -> None:
6149+
code = """
6150+
class A:
6151+
@property
6152+
def test(self):
6153+
'''Docstring'''
6154+
return 42
6155+
6156+
A.test #@
6157+
"""
6158+
node = extract_node(code)
6159+
inferred = next(node.infer())
6160+
assert isinstance(inferred, objects.Property)
6161+
assert isinstance(inferred.doc_node, nodes.Const)
6162+
assert inferred.doc_node.value == "Docstring"
6163+
with pytest.warns(DeprecationWarning) as records:
6164+
assert inferred.doc == "Docstring"
6165+
assert len(records) == 1
6166+
6167+
61486168
def test_recursion_error_inferring_builtin_containers() -> None:
61496169
node = extract_node(
61506170
"""

0 commit comments

Comments
 (0)