diff --git a/python/python-psi-impl/resources/intellij.python.psi.impl.xml b/python/python-psi-impl/resources/intellij.python.psi.impl.xml
index 6d3f13a859ff..2d48452f760c 100644
--- a/python/python-psi-impl/resources/intellij.python.psi.impl.xml
+++ b/python/python-psi-impl/resources/intellij.python.psi.impl.xml
@@ -563,6 +563,7 @@
+
diff --git a/python/python-psi-impl/src/com/jetbrains/python/codeInsight/PyAttrsClassMembersProvider.java b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/PyAttrsClassMembersProvider.java
new file mode 100644
index 000000000000..2f87c8d22e7b
--- /dev/null
+++ b/python/python-psi-impl/src/com/jetbrains/python/codeInsight/PyAttrsClassMembersProvider.java
@@ -0,0 +1,37 @@
+// Copyright 2000-2025 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.jetbrains.python.codeInsight;
+
+import com.intellij.psi.PsiElement;
+import com.jetbrains.python.PyNames;
+import com.jetbrains.python.psi.PyClass;
+import com.jetbrains.python.psi.impl.PyBuiltinCache;
+import com.jetbrains.python.psi.types.PyClassMembersProviderBase;
+import com.jetbrains.python.psi.types.PyClassType;
+import com.jetbrains.python.psi.types.TypeEvalContext;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static com.jetbrains.python.codeInsight.PyDataclassesKt.parseDataclassParameters;
+
+/**
+ * Adds member __attrs_attrs__ caused by decorator @attrs.define
+ */
+public final class PyAttrsClassMembersProvider extends PyClassMembersProviderBase {
+
+ @Override
+ public @NotNull Collection getMembers(PyClassType clazz, PsiElement location, @NotNull TypeEvalContext context) {
+ PyClass pyClass = clazz.getPyClass();
+ PyDataclassParameters dataclassParameters = parseDataclassParameters(pyClass, context);
+ boolean hasAttrs = dataclassParameters != null && dataclassParameters.getType() == PyDataclassParameters.PredefinedType.ATTRS;
+ if (hasAttrs) {
+ PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(pyClass);
+ PyClass objectClass = builtinCache.getClass(PyNames.OBJECT);
+ return List.of(new PyCustomMember("__attrs_attrs__", objectClass));
+ }
+ return Collections.emptyList();
+ }
+
+}
diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java
index 64cace63e508..58fa8738ebb7 100644
--- a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java
+++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java
@@ -389,6 +389,36 @@ public class Py3CompletionTest extends PyTestCase {
);
}
+ // PY-55691
+ public void testAttrsClassMembersProvider() {
+ runWithAdditionalClassEntryInSdkRoots(
+ "../packages",
+ () -> {
+ doTestByText(
+ """
+ import attrs
+
+ @attrs.define
+ class User:
+ password: str
+
+ User().__at"""
+ );
+
+ myFixture.checkResult(
+ """
+ import attrs
+
+ @attrs.define
+ class User:
+ password: str
+
+ User().__attrs_attrs__"""
+ );
+ }
+ );
+ }
+
//PY-28332
public void testImportNamespacePackageInMultipleRoots() {
doMultiFileTest(Arrays.asList("root1/src", "root2/src"));
diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java
index 872e12199c2a..679db3161687 100644
--- a/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/Py3TypeCheckerInspectionTest.java
@@ -2894,4 +2894,35 @@ def foo(param: str | int) -> TypeGuard[str]:
f(a=2)
""");
}
+
+ // PY-55691
+ public void testAttrsDataclassProtocolMatchingDefine() {
+ runWithAdditionalClassEntryInSdkRoots("packages", () ->
+ doTestByText("""
+ import attrs
+
+ @attrs.define
+ class User:
+ password: str
+
+ attrs.fields(User)
+ """)
+ );
+ }
+
+ // PY-55691
+ public void testAttrsDataclassProtocolMatchingFrozen() {
+ runWithAdditionalClassEntryInSdkRoots("packages", () ->
+ doTestByText("""
+ import attrs
+
+ @attrs.frozen
+ class User:
+ password: str
+
+ attrs.fields(User)
+ """)
+ );
+ }
+
}
diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java
index e945f89ba40c..c93fa1324969 100644
--- a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java
@@ -447,4 +447,21 @@ public class Py3UnresolvedReferencesInspectionTest extends PyInspectionTestCase
x.is_integer() # E
""");
}
+
+ // PY-55691
+ public void testAttrsClassMembersProviderAttrsProperty() {
+ runWithAdditionalClassEntryInSdkRoots("packages", () ->
+ doTestByText(
+ """
+ import attrs
+
+ @attrs.define
+ class User:
+ password: str
+
+ User().__attrs_attrs__ # OK
+ """)
+ );
+ }
+
}