diff options
| author | Claudiu Popa <pcmanticore@gmail.com> | 2020-03-06 10:46:26 +0100 |
|---|---|---|
| committer | Claudiu Popa <pcmanticore@gmail.com> | 2020-03-06 10:54:48 +0100 |
| commit | 17a5ee681bcf4aacffcc4ec5afbc3436cfdc4537 (patch) | |
| tree | 10c691821e62b58c4c4a9efd5b29ef828306c24c /tests | |
| parent | 88fd426e14c34cb5771fd6c06f5a1ba50bb03292 (diff) | |
| download | astroid-git-17a5ee681bcf4aacffcc4ec5afbc3436cfdc4537.tar.gz | |
Cache the inference of FunctionDef to prevent property inference mutating locals
When inferring a property, we instantiate a new `objects.Property` object,
which in turn, because it inherits from `FunctionDef`, sets itself in the locals
of the wrapping frame. This means that everytime we infer a property, the locals
are mutated with a new instance of the property.
Using `context` with `path_wrapper` would not have helped, because we call `inferred()`
on functions in multiple places in pylint's codebase.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/unittest_inference.py | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/tests/unittest_inference.py b/tests/unittest_inference.py index 751a4586..49ff6cdc 100644 --- a/tests/unittest_inference.py +++ b/tests/unittest_inference.py @@ -5707,5 +5707,27 @@ def test_self_reference_infer_does_not_trigger_recursion_error(): assert inferred is util.Uninferable +def test_inferring_properties_multiple_time_does_not_mutate_locals_multiple_times(): + code = """ + class A: + @property + def a(self): + return 42 + + A() + """ + node = extract_node(code) + # Infer the class + cls = next(node.infer()) + prop, = cls.getattr("a") + + # Try to infer the property function *multiple* times. `A.locals` should be modified only once + for _ in range(3): + prop.inferred() + a_locals = cls.locals["a"] + # [FunctionDef, Property] + assert len(a_locals) == 2 + + if __name__ == "__main__": unittest.main() |
