Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pylance doesn't recognise attributes obtained from fields #1361

Open
my1e5 opened this issue Oct 23, 2024 · 1 comment
Open

Pylance doesn't recognise attributes obtained from fields #1361

my1e5 opened this issue Oct 23, 2024 · 1 comment

Comments

@my1e5
Copy link
Contributor

my1e5 commented Oct 23, 2024

Consider this MRE

from attrs import define, fields

@define
class A:
    foo: int
    bar: float

f = fields(A)
print(f.foo)
Attribute(name='foo', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=<class 'int'>, converter=None, kw_only=False, inherited=False, on_setattr=None, alias='foo')

This all works fine.

The only thing that isn't working perfectly is Pylance doesn't seem to properly recognise this. It highlights the attribute in white and incorrect hover text is provided.
Untitled

Looking at the types, I found

print(type(f))
<class 'AAttributes'>

But I couldn't find any reference to AAttributes in the codebase.

My question is, is there something that attrs needs to do to make Pylance work here? Or is this a bug/limitation with Pylance and I should open a ticket with them to get support for this?

Thanks.

@hynek
Copy link
Member

hynek commented Nov 9, 2024

attrs creates on-demand classes for attributes for each class:

attrs/src/attr/_make.py

Lines 246 to 270 in 13e9a6a

def _make_attr_tuple_class(cls_name, attr_names):
"""
Create a tuple subclass to hold `Attribute`s for an `attrs` class.
The subclass is a bare tuple with properties for names.
class MyClassAttributes(tuple):
__slots__ = ()
x = property(itemgetter(0))
"""
attr_class_name = f"{cls_name}Attributes"
attr_class_template = [
f"class {attr_class_name}(tuple):",
" __slots__ = ()",
]
if attr_names:
for i, attr_name in enumerate(attr_names):
attr_class_template.append(
f" {attr_name} = _attrs_property(_attrs_itemgetter({i}))"
)
else:
attr_class_template.append(" pass")
globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property}
_compile_and_eval("\n".join(attr_class_template), globs)
return globs[attr_class_name]

Unfortunately, Pyright is not keen on implementing non-PEP features.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants