pylint-dev / pylint-dev/astroid

Progress ``context.clone``

Open
#960 9 comments 3 reactions 0 assignees View on GitHub
Discussion 🤔 Work in progress
Dominant language
Python
Stars
582
Forks
357
Avg merge
1d 1h
Merged PRs (30d)
23

Description

I was looking at the MR to fix `context.clone` and noticed that I didn't really knew anymore what the current status is, which bugs exist, and which have been fixed.

Lets try to gather the information here. Ideally that will make reviewing and working on the remaining issues a lot easier.
/CC: @hippo91, @nelfin, @Pierre-Sassoulas

---

## Original MR

**Fix strong references to mutable objects in context.clone** #927
**Idea**: Fix cycles in `context.path`
**Fixes**: #926
**`pylint` MR to update tests**: PyCQA/pylint#4325

## Issues

1. **`unsupported-membership-test`** => Fixed
**Reason**: `property` members defined on a metaclass were not inferred as data descriptors in a class context on derived classes (e.g. `EnumMeta` -> `Enum` -> `ExampleEnum(Enum)`)
**Ideas**: related to brain_namedtuple_enum?
**Open Issue**: #940
**Open MR**: #941
**Status**: #941 fixes the underlying issue, but in the specific case of `Enum` classes, the `__members__` property reverts to being l `Uninferable`. This means that `unsupported-membership-test` will not be raised, but also any checks on the actual content of `__members__` for subclass-Enum class definitions are not otherwise useful. I have a wip fix for brain_namedtuple_enum at https://github.com/nelfin/astroid/tree/fix/XXX-enum-class-members-brain but I hadn't progressed any further than that
@nelfin: I've updated #941 to fix the issue with `Enum.__members__` and added a MR to pylint for the corresponding tests
PyCQA/pylint#4466
**Assigned**: -
```py
from enum import Enum

class MyEnum(Enum):
CONST1 = "const"

def name_in_enum(name):
# false-positive: unsupported-membership-test
if name in MyEnum.__members__:
return
```

2. **`not-callable`** (1) => Fixed
**Reason**: `delayed_assattr` allowed setting attributes on the `bultins.object` class. Incorrect inference of a type in the `collections.OrderedDict.pop` method (imported by `typing`, hence some observations) meant that `object.prev = None` and `object.next = None` had been "set". (see the sentinel `__marker = object()` on `OrderedDict` and its usage in `pop` and `__delitem__`)
**Open Issue**: #945
**Open MR**: #946
**Open MR `pylint`**: PyCQA/pylint#4348
**Fixed `pylint` issues**: PyCQA/pylint#3595, PyCQA/pylint#3970, PyCQA/pylint#4221, PyCQA/pylint#4232
**Status**: Fixed
**Assigned**: @nelfin
```py
class Example:
def func(self):
pass

whatthe = object()
whatthe.func = None

ex = Example()
ex.func() # false-positive: not-callable
```

3. **`not-callable`** (2)
Not a regression with #926 and #946, that test case fails on current master without those changes.
**Reason**: `data['abc']` is inferred as `None`. The reason seems to be that the name lookup does only find the initial assignment. Thus the change to `lambda: ...` isn't know during the check. A fix would probably require changing the `infer_name` and `lookup` methods.
**Status**: ?
**Assigned**: -
```py
data = {
'abc': None,
}
data['abc'] = lambda: print("Callback called")
data['abc']() # false-positive `not-callable`

CONST = "my_constant"
```

4. **`invalid-sequence-index`**
**Reason**: `instance_getitem` only returns the first call result. Since pylint `safe_infer` only sees one type it assumes that it can go ahead with the `invalid-sequence-index` check
**Status**: No fix yet, need to discuss. I assume that we should "fix"/update `instance_getitem` to return all call results or `Uninferable` if there are multiple types? Should `instance_getitem` just return `method.infer_call_result(...)` instead of `next(method.infer_call_result(...))`. Then pylint `_check_sequence_index` should be updated to check that all inferred types are sequences (a la `no-member` checking if any inferred type has that member)
**Assigned**: -
```py
class DynamicGetitem:
def __getitem__(self, key):
if key == 'attributes':
return []
return {'world': 123}

ex = DynamicGetitem()
ex['hello']['world']
# E1126: Sequence index is not an int, slice, or instance with __index__ (invalid-sequence-index)
```

5. **`no-member`** => Fixed
**Reason**: Regression noticed after change in inference of `typing.Generic`
**Status**: Fixed with #927 and #946
**Open Issue**: #942
**MR for test cases**: https://github.com/PyCQA/pylint/pull/4471
**Assigned**: -
```py
from abc import ABC
from typing import Generic, TypeVar

Anything = TypeVar("Anything")
MoreSpecific = TypeVar("MoreSpecific", str, int)

class A(ABC, Generic[Anything]):
def a_method(self) -> None:
print("hello")

class B(A[MoreSpecific]):
pass
class C(B[str]):
pass

c = C()
c.a_method() # false-positive: no-member
```

## Related
- `pylint` MR with regression test cases (not yet fixed): https://github.com/PyCQA/pylint/pull/4387

## PRs with fixed test cases
https://github.com/PyCQA/astroid/pull/992
https://github.com/PyCQA/pylint/pull/4325
https://github.com/PyCQA/pylint/pull/4348
https://github.com/PyCQA/pylint/pull/4471
https://github.com/PyCQA/pylint/pull/4473

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.