From bbbe129589ea35df9d2974801bd1ab9be131a268 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Wed, 11 Mar 2015 17:19:40 +0300 Subject: [PATCH] PY-4387 First version of "Convert Module to Package" refactoring --- python/src/META-INF/python-core.xml | 7 ++ .../PyConvertModuleToPackageAction.java | 83 +++++++++++++++++++ .../simple/after/a/__init__.py | 5 ++ .../convertModuleToPackage/simple/after/b.py | 0 .../convertModuleToPackage/simple/before/a.py | 5 ++ .../convertModuleToPackage/simple/before/b.py | 0 .../PyConvertModuleToPackageTest.java | 32 +++++++ 7 files changed, 132 insertions(+) create mode 100644 python/src/com/jetbrains/python/refactoring/packages/PyConvertModuleToPackageAction.java create mode 100644 python/testData/refactoring/convertModuleToPackage/simple/after/a/__init__.py create mode 100644 python/testData/refactoring/convertModuleToPackage/simple/after/b.py create mode 100644 python/testData/refactoring/convertModuleToPackage/simple/before/a.py create mode 100644 python/testData/refactoring/convertModuleToPackage/simple/before/b.py create mode 100644 python/testSrc/com/jetbrains/python/refactoring/PyConvertModuleToPackageTest.java diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index 64623e437767..cc01ea7d3952 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -745,6 +745,13 @@ + + + + + diff --git a/python/src/com/jetbrains/python/refactoring/packages/PyConvertModuleToPackageAction.java b/python/src/com/jetbrains/python/refactoring/packages/PyConvertModuleToPackageAction.java new file mode 100644 index 000000000000..0edc3389d1b0 --- /dev/null +++ b/python/src/com/jetbrains/python/refactoring/packages/PyConvertModuleToPackageAction.java @@ -0,0 +1,83 @@ +package com.jetbrains.python.refactoring.packages; + +import com.google.common.annotations.VisibleForTesting; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiManager; +import com.jetbrains.python.PyNames; +import com.jetbrains.python.psi.PyFile; +import com.jetbrains.python.psi.PyUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; + +import static com.jetbrains.python.psi.PyUtil.as; + +/** + * @author Mikhail Golubev + */ +public class PyConvertModuleToPackageAction extends AnAction { + private static final Logger LOG = Logger.getInstance(PyConvertModuleToPackageAction.class); + + @Override + public void actionPerformed(AnActionEvent e) { + final PyFile pyFile = getPythonFile(e); + assert pyFile != null; + final Project project = e.getProject(); + if (project != null) { + createPackageFromModule(pyFile, project); + } + } + + @VisibleForTesting + public static void createPackageFromModule(@NotNull final PyFile file, @NotNull Project project) { + WriteCommandAction.runWriteCommandAction(project, new Runnable() { + public void run() { + final VirtualFile vFile = file.getVirtualFile(); + final VirtualFile parentDir = vFile.getParent(); + try { + final VirtualFile packageDir = parentDir.createChildDirectory(this, vFile.getNameWithoutExtension()); + vFile.move(this, packageDir); + vFile.rename(this, PyNames.INIT_DOT_PY); + } + catch (IOException e) { + LOG.error(e); + } + } + }); + } + + + @Override + public void update(AnActionEvent e) { + final boolean enabled = isEnabled(e); + e.getPresentation().setVisible(enabled); + e.getPresentation().setEnabled(enabled); + } + + @Nullable + private static PyFile getPythonFile(@NotNull AnActionEvent e) { + final VirtualFile vFile = e.getData(CommonDataKeys.VIRTUAL_FILE); + final Project project = e.getData(CommonDataKeys.PROJECT); + if (project != null && vFile != null && !vFile.isDirectory()) { + final PsiManager psiManager = PsiManager.getInstance(project); + return as(psiManager.findFile(vFile), PyFile.class); + } + return null; + } + + private static boolean isEnabled(@NotNull AnActionEvent e) { + final Project project = e.getData(CommonDataKeys.PROJECT); + if (project == null) { + return false; + } + final PyFile file = getPythonFile(e); + return file != null && !PyUtil.isPackage(file); + } +} diff --git a/python/testData/refactoring/convertModuleToPackage/simple/after/a/__init__.py b/python/testData/refactoring/convertModuleToPackage/simple/after/a/__init__.py new file mode 100644 index 000000000000..6be3d998b68a --- /dev/null +++ b/python/testData/refactoring/convertModuleToPackage/simple/after/a/__init__.py @@ -0,0 +1,5 @@ +import b + + +def func(): + print(b) diff --git a/python/testData/refactoring/convertModuleToPackage/simple/after/b.py b/python/testData/refactoring/convertModuleToPackage/simple/after/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/convertModuleToPackage/simple/before/a.py b/python/testData/refactoring/convertModuleToPackage/simple/before/a.py new file mode 100644 index 000000000000..6be3d998b68a --- /dev/null +++ b/python/testData/refactoring/convertModuleToPackage/simple/before/a.py @@ -0,0 +1,5 @@ +import b + + +def func(): + print(b) diff --git a/python/testData/refactoring/convertModuleToPackage/simple/before/b.py b/python/testData/refactoring/convertModuleToPackage/simple/before/b.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyConvertModuleToPackageTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyConvertModuleToPackageTest.java new file mode 100644 index 000000000000..68d3bdd2bc5d --- /dev/null +++ b/python/testSrc/com/jetbrains/python/refactoring/PyConvertModuleToPackageTest.java @@ -0,0 +1,32 @@ +package com.jetbrains.python.refactoring; + +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.testFramework.PlatformTestUtil; +import com.jetbrains.python.fixtures.PyTestCase; +import com.jetbrains.python.psi.PyFile; + +import static com.jetbrains.python.refactoring.packages.PyConvertModuleToPackageAction.createPackageFromModule; + +/** + * @author Mikhail Golubev + */ +public class PyConvertModuleToPackageTest extends PyTestCase { + + // PY-4387 + public void testSimple() throws Exception { + final String rootBeforePath = getTestName(true) + "/before"; + final String rootAfterPath = getTestName(true) + "/after"; + final VirtualFile copiedDirectory = myFixture.copyDirectoryToProject(rootBeforePath, ""); + myFixture.configureByFile("a.py"); + + final PyFile moduleToConvert = assertInstanceOf(myFixture.getFile(), PyFile.class); + createPackageFromModule(moduleToConvert, myFixture.getProject()); + + PlatformTestUtil.assertDirectoriesEqual(copiedDirectory, getVirtualFileByName(getTestDataPath() +rootAfterPath)); + } + + @Override + protected String getTestDataPath() { + return super.getTestDataPath() + "/refactoring/convertModuleToPackage/"; + } +}