astroid
astroid copied to clipboard
Add the ``__annotations__`` attribute to the ``ClassDef`` object model.
Type of Changes
| Type | |
|---|---|
| ✓ | :bug: Bug fix |
| :sparkles: New feature | |
| :hammer: Refactoring | |
| :scroll: Docs |
Description
Add the __annotations__ attribute to the ClassDef object model.
Pylint now does not emit a no-member error when accessing __annotations__ in the following cases:
case 1.
class Test:
print(__annotations__)
case 2.
from typing import TypedDict
OtherTypedDict = TypedDict('OtherTypedDict', {'a': int, 'b': str})
print(OtherTypedDict.__annotations__)
case 1 is similar to the behaviour of some of the other special attributes:
class Test:
print(__module__)
print(__qualname__)
print(__annotations__)
It turns out that this fix also fixed case 2. However, it's still unclear why case 2 was only a false positive for Python 3.9 and older 😬
Closes pylint-dev/pylint#7126
Codecov Report
All modified and coverable lines are covered by tests :white_check_mark:
Project coverage is 92.72%. Comparing base (
2c38c02) to head (90f6f67). Report is 185 commits behind head on main.
Additional details and impacted files
@@ Coverage Diff @@
## main #2431 +/- ##
==========================================
- Coverage 92.78% 92.72% -0.06%
==========================================
Files 94 94
Lines 11098 10996 -102
==========================================
- Hits 10297 10196 -101
+ Misses 801 800 -1
| Flag | Coverage Δ | |
|---|---|---|
| linux | 92.60% <100.00%> (+0.01%) |
:arrow_up: |
| pypy | 92.72% <100.00%> (-0.06%) |
:arrow_down: |
| windows | 92.70% <100.00%> (+0.02%) |
:arrow_up: |
Flags with carried forward coverage won't be shown. Click here to find out more.
| Files with missing lines | Coverage Δ | |
|---|---|---|
| astroid/interpreter/objectmodel.py | 93.27% <100.00%> (+0.02%) |
:arrow_up: |
| astroid/nodes/scoped_nodes/scoped_nodes.py | 92.77% <100.00%> (+0.25%) |
:arrow_up: |
I'm fine with the change, but should this behind a version flag?
See https://docs.python.org/3/howto/annotations.html. It seems it was only added to all objects in 3.10+?
I see what you mean @DanielNoord great point. On Python 3.8, for example, we can demonstrate your point (this corresponds to case 2 in the description above):
>>> class Fruit:
... pass
...
>>> Fruit().__annotations__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Fruit' object has no attribute '__annotations__'
Now, let's look at case 1 on Python 3.8:
>>> class Fruit:
... print(__annotations__)
...
{}
>>>
Without the fix, Pylint does emit the error here. At this moment I don't know if it's better to make a distinction or keep it as-is but I'm open to ideas.
I think a distinction would be better as that better represents the actual versions right?
I would need to investigate a bit further @DanielNoord but my thinking is that we need the attribute anyway to satisfy both cases; so is the distinction necessary? Possibly but I need to see how that could work
However, it's still unclear why case 2 was only a false positive for Python 3.9 and older 😬
At a glance, I expect that's because on 3.9 and below, the base class __annotations__ was returned.