diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java b/python/python-psi-impl/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java index 8b0eef5f4fa5..b9b3ed1505d7 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/resolve/PyResolveUtil.java @@ -179,11 +179,23 @@ public final class PyResolveUtil { : ContainerUtil.map(resolveImportedElementQNameLocally((PyReferenceExpression)qualifier), qn -> qn.append(name)); } else { - return fullMultiResolveLocally(expression, new HashSet<>()) + List result = fullMultiResolveLocally(expression, new HashSet<>()) .select(PyImportElement.class) .map(PyResolveUtil::getImportedElementQName) .nonNull() .toList(); + if (!result.isEmpty()) return result; + if (expression.getName() == null) return result; + + PsiFile containingFile = expression.getContainingFile(); + if (!(containingFile instanceof PyFile)) return result; + List fromImports = ((PyFile)containingFile).getFromImports(); + return StreamEx.of(fromImports) + .filter(it -> it.isStarImport()) + .map(it -> it.getImportSourceQName()) + .nonNull() + .map(it -> it.append(expression.getName())) + .toList(); } } diff --git a/python/testData/resolve/DataclassFieldsDataclassesStarImport.py b/python/testData/resolve/DataclassFieldsDataclassesStarImport.py new file mode 100644 index 000000000000..dbafda9a83cf --- /dev/null +++ b/python/testData/resolve/DataclassFieldsDataclassesStarImport.py @@ -0,0 +1,10 @@ +from dataclasses import * + + +@dataclass(eq=True) +class Foo: + foo: int + + +print(Foo(foo=42)) +# \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/Py3ResolveTest.java b/python/testSrc/com/jetbrains/python/Py3ResolveTest.java index 47127a86547c..01f0d9cdf98c 100644 --- a/python/testSrc/com/jetbrains/python/Py3ResolveTest.java +++ b/python/testSrc/com/jetbrains/python/Py3ResolveTest.java @@ -777,6 +777,11 @@ public class Py3ResolveTest extends PyResolveTestCase { assertNull(doResolve()); } + // PY-36158 + public void testDataclassFieldsDataclassesStarImport() { + assertResolvesTo(PyTargetExpression.class, "foo"); + } + public void testInstanceAttrAbove() { assertResolvesTo(PyTargetExpression.class, "foo"); } diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3ArgumentListInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3ArgumentListInspectionTest.java index 39df454b73a4..80cf0db1de35 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3ArgumentListInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3ArgumentListInspectionTest.java @@ -18,6 +18,20 @@ public class Py3ArgumentListInspectionTest extends PyInspectionTestCase { return ourPyLatestDescriptor; } + // PY-36158 + public void testDataclassesStarImportNoUnexpectedArgumentWarning() { + doTestByText("from dataclasses import *\n" + + "\n" + + "\n" + + "@dataclass(eq=True)\n" + + "class Foo:\n" + + " a: float\n" + + " b: float\n" + + "\n" + + "\n" + + "print(Foo(1, 2))\n"); + } + // PY-50404 public void testPassingKeywordArgumentsToParamSpec() { doTestByText("""