From 6d2db28b86b9839b3a9c4448f6762dc18bef16f6 Mon Sep 17 00:00:00 2001 From: Morgan Bartholomew Date: Mon, 24 Nov 2025 11:53:18 +1000 Subject: [PATCH] [PY-6591] use `PyCodeInsightSettings.PREFER_FROM_IMPORT` when moving module reference (cherry picked from commit 2458902032ff1078689a2a641dfaa29e522148a5) IJ-MR-183300 GitOrigin-RevId: f101d8aac2ad92af83ad6716a15865238856abb7 --- .../classes/PyClassRefactoringUtil.java | 24 ++++++++++++++++++- .../after/src/lib/__init__.py | 0 .../after/src/lib/dst.py | 5 ++++ .../after/src/lib/mod.py | 0 .../after/src/lib/src.py | 2 ++ .../before/src/lib/__init__.py | 0 .../before/src/lib/dst.py | 0 .../before/src/lib/mod.py | 0 .../before/src/lib/src.py | 4 ++++ .../python/refactoring/PyMoveTest.java | 12 ++++++++++ 10 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/__init__.py create mode 100644 python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/dst.py create mode 100644 python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/mod.py create mode 100644 python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/src.py create mode 100644 python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/__init__.py create mode 100644 python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/dst.py create mode 100644 python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/mod.py create mode 100644 python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/src.py diff --git a/python/python-psi-impl/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java b/python/python-psi-impl/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java index f502225a0af7..0b1630a85694 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java +++ b/python/python-psi-impl/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java @@ -25,11 +25,13 @@ import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyPsiBundle; +import com.jetbrains.python.codeInsight.PyCodeInsightSettings; import com.jetbrains.python.codeInsight.imports.AddImportHelper; import com.jetbrains.python.codeInsight.imports.PyImportOptimizer; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyImportedModule; import com.jetbrains.python.psi.impl.PyPsiUtils; +import com.jetbrains.python.psi.resolve.QualifiedNameFinder; import com.jetbrains.python.refactoring.PyPsiRefactoringUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -273,7 +275,27 @@ public final class PyClassRefactoringUtil { if (PsiTreeUtil.isAncestor(targetNode.getContainingFile(), target, false)) return; if (ArrayUtil.contains(target, otherMovedElements)) return; if (target instanceof PyFile || target instanceof PsiDirectory) { - PyPsiRefactoringUtil.insertImport(targetNode, target, asName, useFromImport != null ? useFromImport : true); + boolean preferFromImport = useFromImport != null ? useFromImport : true; + boolean isUsedAsQualifier = sourceNode.getParent() instanceof PyQualifiedExpression && + ((PyQualifiedExpression)sourceNode.getParent()).getQualifier() == sourceNode; + boolean shouldQualifyReference = target instanceof PyFile && + PyCodeInsightSettings.getInstance().PREFER_FROM_IMPORT && + useFromImport != null && useFromImport && + asName == null && + !isUsedAsQualifier; + if (shouldQualifyReference) { + preferFromImport = false; + } + PyPsiRefactoringUtil.insertImport(targetNode, target, asName, preferFromImport); + if (shouldQualifyReference) { + QualifiedName canonicalPath = QualifiedNameFinder.findCanonicalImportPath(target, targetNode); + if (canonicalPath != null && sourceNode.isValid()) { + String qualifiedReference = canonicalPath.toString(); + PyElementGenerator generator = PyElementGenerator.getInstance(sourceNode.getProject()); + PyExpression newExpr = generator.createExpressionFromText(LanguageLevel.forElement(sourceNode), qualifiedReference); + sourceNode.replace(newExpr); + } + } } else { PyPsiRefactoringUtil.insertImport(targetNode, target, asName, true); diff --git a/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/__init__.py b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/dst.py b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/dst.py new file mode 100644 index 000000000000..c6f302fd077c --- /dev/null +++ b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/dst.py @@ -0,0 +1,5 @@ +import lib.mod + + +def usage(): + lib.mod diff --git a/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/mod.py b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/mod.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/src.py b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/src.py new file mode 100644 index 000000000000..139597f9cb07 --- /dev/null +++ b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/after/src/lib/src.py @@ -0,0 +1,2 @@ + + diff --git a/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/__init__.py b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/dst.py b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/dst.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/mod.py b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/mod.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/src.py b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/src.py new file mode 100644 index 000000000000..4ebfa84010aa --- /dev/null +++ b/python/testData/refactoring/move/importForMovedElementWithPreferredQualifiedImportStyleModule/before/src/lib/src.py @@ -0,0 +1,4 @@ +from lib import mod + +def usage(): + mod \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java index da52b86564bc..bc8ec38f7546 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java @@ -283,6 +283,18 @@ public class PyMoveTest extends PyTestCase { } } + @TestFor(issues="PY-6591") + public void testImportForMovedElementWithPreferredQualifiedImportStyleModule() { + final boolean defaultImportStyle = PyCodeInsightSettings.getInstance().PREFER_FROM_IMPORT; + try { + PyCodeInsightSettings.getInstance().PREFER_FROM_IMPORT = true; + doMoveSymbolTest("usage", "lib/dst.py"); + } + finally { + PyCodeInsightSettings.getInstance().PREFER_FROM_IMPORT = defaultImportStyle; + } + } + @TestFor(issues="PY-84659") public void testQualifiedUsageRespectsPreferFromImport() { final boolean defaultImportStyle = PyCodeInsightSettings.getInstance().PREFER_FROM_IMPORT;