From 992b5a3fcd7a44a6122cdd4d0ea4c71e119ef7e1 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 16 Feb 2011 16:18:28 +0100 Subject: [PATCH 01/17] @NotNull, fix calculating SDK for out of project files during completion (PY-1975) --- python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java | 2 +- .../src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java index 3b39bfd5cd0a..8d487ffea4ea 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBuiltinCache.java @@ -75,7 +75,7 @@ public class PyBuiltinCache { sdk = PythonSdkType.findPythonSdk(module); } else { - final VirtualFile vfile = psifile.getVirtualFile(); + final VirtualFile vfile = psifile instanceof PsiFile ? ((PsiFile) psifile).getOriginalFile().getVirtualFile() : psifile.getVirtualFile(); if (vfile != null) { // reality final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(project); sdk = projectRootManager.getProjectSdk(); diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 0113fd88def7..2ac7917f8e9f 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -437,7 +437,7 @@ public class ResolveImportUtil { // no module, another way to look in SDK roots final PsiFile elt_psifile = elt.getContainingFile(); if (elt_psifile != null) { // formality - final VirtualFile elt_vfile = elt_psifile.getVirtualFile(); + final VirtualFile elt_vfile = elt_psifile.getOriginalFile().getVirtualFile(); if (elt_vfile != null) { // reality final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(elt.getProject()).getFileIndex(); final List orderEntries = fileIndex.getOrderEntriesForFile(elt_vfile); From 5cbfad8b1c3fd227bb3ec219dcbad786d61919ed Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 16 Feb 2011 16:33:44 +0100 Subject: [PATCH 02/17] fix 'unhashable instance' exception in generator --- python/helpers/generator3.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 52b58bf7dffb..d5d171a9410f 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -1432,18 +1432,18 @@ class ModuleRedeclarator(object): @param indent indentation level @param p_class the class that contains this function as a method @param p_modname module name - @param seen {func: name} map of functions already seen in the same namespace - """ + @param seen {id(func): name} map of functions already seen in the same namespace; + id() because *some* functions are unhashable (eg _elementtree.Comment in py2.7) """ action("redoing func %r of class %r", p_name, p_class) if seen is not None: - other_func = seen.get(p_func, None) + other_func = seen.get(id(p_func), None) if other_func and getattr(other_func, "__doc__", None) is getattr(p_func, "__doc__", None): # _bisect.bisect == _bisect.bisect_right in py31, but docs differ - out(indent, p_name, " = ", seen[p_func]) + out(indent, p_name, " = ", seen[id(p_func)]) out(indent, "") return else: - seen[p_func] = p_name + seen[id(p_func)] = p_name # real work classname = p_class and p_class.__name__ or None if p_class and hasattr(p_class, '__mro__'): From 8c0ef87f2603fa2f34ec19327764f13e089dab89 Mon Sep 17 00:00:00 2001 From: Dmitry Cheryasov Date: Wed, 16 Feb 2011 17:42:23 +0200 Subject: [PATCH 03/17] Fix for the strange case of unhashable functions in py27/win --- python/helpers/generator3.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 52b58bf7dffb..cfe2c15d0bc5 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -1432,18 +1432,19 @@ class ModuleRedeclarator(object): @param indent indentation level @param p_class the class that contains this function as a method @param p_modname module name - @param seen {func: name} map of functions already seen in the same namespace + @param seen {id(func): name} map of functions already seen in the same namespace; + id() because *some* functions are unhashable (eg _elementtree.Comment in py2.7) """ action("redoing func %r of class %r", p_name, p_class) if seen is not None: - other_func = seen.get(p_func, None) + other_func = seen.get(id(p_func), None) if other_func and getattr(other_func, "__doc__", None) is getattr(p_func, "__doc__", None): # _bisect.bisect == _bisect.bisect_right in py31, but docs differ - out(indent, p_name, " = ", seen[p_func]) + out(indent, p_name, " = ", seen[id(p_func)]) out(indent, "") return else: - seen[p_func] = p_name + seen[id(p_func)] = p_name # real work classname = p_class and p_class.__name__ or None if p_class and hasattr(p_class, '__mro__'): From 409cd0842b71a4f983727bdf01663488f204a929 Mon Sep 17 00:00:00 2001 From: Dmitry Cheryasov Date: Wed, 16 Feb 2011 18:10:45 +0200 Subject: [PATCH 04/17] PY-1868: auto-insert 'import' after qualified import refs --- .../psi/impl/PyImportReferenceImpl.java | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java index fb39d6a9fe69..87dde5032591 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportReferenceImpl.java @@ -11,10 +11,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Iconable; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiErrorElement; -import com.intellij.psi.PsiFile; +import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ArrayUtil; @@ -94,7 +91,23 @@ public class PyImportReferenceImpl extends PyReferenceImpl { // qualifier's type must be module, it should know how to complete PyType type = qualifier.getType(TypeEvalContext.fast()); if (type != null) { - return getTypeCompletionVariants(myElement, type); + Object[] variants = getTypeCompletionVariants(myElement, type); + if (!alreadyHasImportKeyword()) { + for (int i=0; i < variants.length; i+=1) { + Object item = variants[i]; + if (item instanceof LookupElementBuilder) { + variants[i] = ((LookupElementBuilder)item).setInsertHandler(ImportKeywordHandler.INSTANCE); + } + else if (item instanceof PsiNamedElement) { + final PsiNamedElement element = (PsiNamedElement)item; + variants[i] = LookupElementBuilder + .create(element.getName()) // it can't really have null name + .setIcon(element.getIcon(0)) + .setInsertHandler(ImportKeywordHandler.INSTANCE); + } + } + } + return variants; } else { return ArrayUtil.EMPTY_OBJECT_ARRAY; @@ -106,6 +119,19 @@ public class PyImportReferenceImpl extends PyReferenceImpl { } } + private boolean alreadyHasImportKeyword() { + ASTNode node = myElement.getNode(); + while (node != null) { + final IElementType node_type = node.getElementType(); + if (node_type == PyTokenTypes.IMPORT_KEYWORD) { + return true; + } + node = node.getTreeNext(); + } + return false; + } + + class ImportVariantCollector { private final PsiFile myCurrentFile; private final Set myNamesAlready; @@ -209,18 +235,6 @@ public class PyImportReferenceImpl extends PyReferenceImpl { } } - private boolean alreadyHasImportKeyword() { - ASTNode node = myElement.getNode(); - while (node != null) { - final IElementType node_type = node.getElementType(); - if (node_type == PyTokenTypes.IMPORT_KEYWORD) { - return true; - } - node = node.getTreeNext(); - } - return false; - } - private void addImportedNames(@NotNull PyImportElement[] import_elts) { for (PyImportElement ielt : import_elts) { PyReferenceExpression ref = ielt.getImportReference(); From 4cba4f70424110468584a1f1ebd4adcd9c8a5a08 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Wed, 16 Feb 2011 20:22:48 +0300 Subject: [PATCH 05/17] Fixed resolveModulesInRoots to make work resolve for django project name. Needed to fix PY-2239. --- .../python/psi/resolve/ResolveImportUtil.java | 92 ++++++++++--------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index 0113fd88def7..937b98de14e5 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -2,7 +2,6 @@ package com.jetbrains.python.psi.resolve; import com.google.common.collect.Sets; import com.intellij.facet.FacetManager; -import com.intellij.facet.ProjectFacetManager; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtil; @@ -229,17 +228,7 @@ public class ResolveImportUtil { } List found_in_roots = resolveModulesInRoots(qualifiedName, source_file); if (found_in_roots.size() > 0) return found_in_roots; - // resolve the name considering every source root as a package dir, as if it's a deployed package. django console does so. - boolean has_djando_facet = false; - final Module source_module = ModuleUtil.findModuleForPsiElement(source_file); - if (source_module != null) { - has_djando_facet = FacetManager.getInstance(source_module).getFacetByType(DjangoFacetType.ID) != null; - } - if (has_djando_facet) { - ResolveInRootVisitor visitor = new ResolveInRootAsTopPackageVisitor(qualifiedName, source_file.getManager(), source_file, true); - visitRoots(source_file, visitor); - return visitor.results; - } + return Collections.emptyList(); } } @@ -274,7 +263,7 @@ public class ResolveImportUtil { } @Nullable - public static PsiElement resolveModuleInRoots(@NotNull PyQualifiedName moduleQualifiedName, PsiElement foothold) { + public static PsiElement resolveModuleInRoots(@NotNull PyQualifiedName moduleQualifiedName, @Nullable PsiElement foothold) { final List candidates = resolveModulesInRoots(moduleQualifiedName, foothold); return candidates.isEmpty() ? null : candidates.get(0); } @@ -287,7 +276,7 @@ public class ResolveImportUtil { * @return the list of matching directories or files, or an empty list if nothing was found */ @NotNull - public static List resolveModulesInRoots(@NotNull PyQualifiedName moduleQualifiedName, PsiElement foothold) { + public static List resolveModulesInRoots(@NotNull PyQualifiedName moduleQualifiedName, @Nullable PsiElement foothold) { if (foothold == null || !foothold.isValid()) return Collections.emptyList(); PsiFile footholdFile = foothold.getContainingFile(); if (footholdFile == null || !footholdFile.isValid()) return Collections.emptyList(); @@ -299,11 +288,31 @@ public class ResolveImportUtil { return cachedResults; } } - ResolveInRootVisitor visitor = new ResolveInRootVisitor(moduleQualifiedName, foothold.getManager(), footholdFile, true); - visitRoots(foothold, visitor); + + List results = visitRoots(moduleQualifiedName, foothold); + if (cache != null) { - cache.put(moduleQualifiedName, visitor.results); + cache.put(moduleQualifiedName, results); } + return results; + } + + private static List visitRoots(@NotNull PyQualifiedName moduleQualifiedName, @NotNull PsiElement foothold) { + PsiFile footholdFile = foothold.getContainingFile(); + // resolve the name considering every source root as a package dir, as if it's a deployed package. django console does so. + boolean has_djando_facet = false; + final Module source_module = ModuleUtil.findModuleForPsiElement(foothold); + if (source_module != null) { + has_djando_facet = FacetManager.getInstance(source_module).getFacetByType(DjangoFacetType.ID) != null; + } + ResolveInRootVisitor visitor; + if (has_djando_facet) { + visitor = new ResolveInRootAsTopPackageVisitor(moduleQualifiedName, foothold.getManager(), footholdFile, true); + } + else { + visitor = new ResolveInRootVisitor(moduleQualifiedName, foothold.getManager(), footholdFile, true); + } + visitRoots(foothold, visitor); return visitor.results; } @@ -513,7 +522,7 @@ public class ResolveImportUtil { /** * Looks for a name among element's module's roots; if there's no module, then among project's roots. * - * @param context PSI element that defines the module and/or the project. + * @param context PSI element that defines the module and/or the project. * @param refName module name to be found among roots. * @return a PsiFile, a child of a root. */ @@ -559,7 +568,7 @@ public class ResolveImportUtil { static class ResolveInRootVisitor implements RootVisitor { final PsiFile myFootholdFile; - private final boolean myCheckForPackage; + final boolean myCheckForPackage; final @NotNull PyQualifiedName myQualifiedName; final @NotNull PsiManager myPsiManager; final List results = new ArrayList(); @@ -582,17 +591,17 @@ public class ResolveImportUtil { if (module != null) { results.add(module); } + return true; } @Nullable - private PsiElement resolveInRoot(VirtualFile root, - PyQualifiedName qualifiedName, - PsiManager psiManager, - @Nullable PsiFile foothold_file, - boolean checkForPackage) { + protected PsiElement resolveInRoot(VirtualFile root, + PyQualifiedName qualifiedName, + PsiManager psiManager, + @Nullable PsiFile foothold_file, + boolean checkForPackage) { PsiElement module = root.isDirectory() ? psiManager.findDirectory(root) : psiManager.findFile(root); - module = patchModule(module, qualifiedName); if (module == null) return null; for (String component : qualifiedName.getComponents()) { if (component == null) { @@ -603,18 +612,6 @@ public class ResolveImportUtil { } return module; } - - /** - * @param root_module file or dir representing a module's root. - * @param name what we try to resolve - * @return altered parent module; this implementation returns root_module unmodified. - */ - @Nullable - @SuppressWarnings({"MethodMayBeStatic"}) - protected PsiElement patchModule(PsiElement root_module, PyQualifiedName name) { - return root_module; - } - } /** @@ -629,13 +626,24 @@ public class ResolveImportUtil { super(qName, psiManager, foothold_file, checkForPackage); } - @Nullable @Override - protected PsiElement patchModule(PsiElement root_module, PyQualifiedName name) { - if (name.matchesPrefix(PyQualifiedName.fromDottedString(((PsiNamedElement)root_module).getName()))) { - return root_module.getParent(); + public boolean visitRoot(VirtualFile root) { + if (!root.isValid()) { + return true; } - return null; + PsiElement module = resolveInRoot(root, myQualifiedName, myPsiManager, myFootholdFile, myCheckForPackage); + if (module != null) { + results.add(module); + } + + if (myQualifiedName.matchesPrefix(PyQualifiedName.fromDottedString(root.getName()))) { + module = resolveInRoot(root.getParent(), myQualifiedName, myPsiManager, myFootholdFile, myCheckForPackage); + if (module != null) { + results.add(module); + } + } + + return true; } } From 795031fdfe081b898a3d008c862844d33b8e096d Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 16 Feb 2011 19:41:22 +0100 Subject: [PATCH 06/17] in debug mode, exit if failed to import name --- python/helpers/generator3.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index cfe2c15d0bc5..20dd7ac6d7f1 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -2085,6 +2085,8 @@ if __name__ == "__main__": __import__(name) # sys.modules will fill up with what we want except ImportError: report("Name %r failed to import", name) + if debug_mode: + sys.exit(1) continue if my_finder: From 9fe76612007b634169ac7a67a8956a7415fdcc63 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 16 Feb 2011 20:21:01 +0100 Subject: [PATCH 07/17] diagnostics for ImportError --- python/helpers/generator3.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 20dd7ac6d7f1..4523a2a23477 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -2084,7 +2084,8 @@ if __name__ == "__main__": try: __import__(name) # sys.modules will fill up with what we want except ImportError: - report("Name %r failed to import", name) + exctype, value = sys.exc_info()[:2] + report("Name %r failed to import: %r", name, str(value)) if debug_mode: sys.exit(1) continue From 2cc29dd319b8cc4003ef70c37ac2cf5364eaaa2c Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 16 Feb 2011 20:30:12 +0100 Subject: [PATCH 08/17] fix another incompatibility of generator3 with PyQt4 --- python/helpers/generator3.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 4523a2a23477..958c0bb39349 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -1703,11 +1703,15 @@ class ModuleRedeclarator(object): Intended for built-in modules and thus does not handle import statements. @param p_name name of module """ - action("redong module %r", p_name) + action("redoing module %r", p_name) self.redoSimpleHeader(p_name) # find whatever other self.imported_modules the module knows; effectively these are imports module_type = type(sys) - for item_name, item in self.module.__dict__.items(): + for item_name in self.module.__dict__.keys(): + try: + item = self.module.__dict__[item_name] + except: + continue if isinstance(item, module_type): self.imported_modules[item_name] = item self.addImportHeaderIfNeeded() From ccfda7332f0a6e3f13c97b1b6cf3354222cd1bc1 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 16 Feb 2011 20:56:31 +0100 Subject: [PATCH 09/17] even further crash-proof import restoration --- python/helpers/generator3.py | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 958c0bb39349..94ecd9a4a95f 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -1692,20 +1692,8 @@ class ModuleRedeclarator(object): out(0, "# from file " + self.module.__file__) self.outDocAttr(out, self.module, 0) - def addImportHeaderIfNeeded(self): - if self.imports_buf.isEmpty(): - self.imports_buf.out(0, "") - self.imports_buf.out(0, "# imports") - def redo(self, p_name, imported_module_names): - """ - Restores module declarations. - Intended for built-in modules and thus does not handle import statements. - @param p_name name of module - """ - action("redoing module %r", p_name) - self.redoSimpleHeader(p_name) - # find whatever other self.imported_modules the module knows; effectively these are imports + def redoImports(self): module_type = type(sys) for item_name in self.module.__dict__.keys(): try: @@ -1721,6 +1709,28 @@ class ModuleRedeclarator(object): else: self.imports_buf.out(0, item_name, " = None # ??? name unknown; ", ref_notice) + def addImportHeaderIfNeeded(self): + if self.imports_buf.isEmpty(): + self.imports_buf.out(0, "") + self.imports_buf.out(0, "# imports") + + def redo(self, p_name, imported_module_names): + """ + Restores module declarations. + Intended for built-in modules and thus does not handle import statements. + @param p_name name of module + """ + action("redoing module %r %r", p_name, str(self.module)) + self.redoSimpleHeader(p_name) + + # find whatever other self.imported_modules the module knows; effectively these are imports + try: + self.redoImports() + except: + pass + + module_type = type(sys) + # group what else we have into buckets vars_simple = {} vars_complex = {} From 8f1d502811004f4b5c322be601d2626fb28050cc Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Wed, 16 Feb 2011 21:02:54 +0100 Subject: [PATCH 10/17] fix testdata --- python/testData/completion/importItself.after.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/testData/completion/importItself.after.py b/python/testData/completion/importItself.after.py index 17090ac3c5fd..5fc2231a302c 100644 --- a/python/testData/completion/importItself.after.py +++ b/python/testData/completion/importItself.after.py @@ -1 +1 @@ -from package1.submodule2 \ No newline at end of file +from package1.submodule2 import \ No newline at end of file From 5845bc2fd1e7c5d00b299a2c7cbd415d28674a70 Mon Sep 17 00:00:00 2001 From: Dmitry Cheryasov Date: Thu, 17 Feb 2011 02:32:18 +0200 Subject: [PATCH 11/17] Fix py2.7 + PyQt 4.7.3 on win32 failing on isinstance() --- python/helpers/generator3.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index cfe2c15d0bc5..34870b7a8f0b 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -1708,7 +1708,7 @@ class ModuleRedeclarator(object): # find whatever other self.imported_modules the module knows; effectively these are imports module_type = type(sys) for item_name, item in self.module.__dict__.items(): - if isinstance(item, module_type): + if type(item) is module_type: # not isinstance, py2.7 + PyQt4.QtCore on windows have a bug here self.imported_modules[item_name] = item self.addImportHeaderIfNeeded() ref_notice = getattr(item, "__file__", str(item)) @@ -1960,7 +1960,7 @@ def redoModule(name, fname, imported_module_names): # sys.modules mod = sys.modules[name] if not mod: - sys.stderr.write("Failed to find imported module in sys.modules") + report("Failed to find imported module in sys.modules") #sys.exit(0) if update_mode and hasattr(mod, "__file__"): @@ -2101,7 +2101,7 @@ if __name__ == "__main__": # if module has __file__ defined, it has Python source code and doesn't need a skeleton if m not in old_modules and m not in imported_module_names and m != name and not hasattr(sys.modules[m], '__file__'): if not quiet: - sys.stdout.write(m + "\n") + say(m) sys.stdout.flush() fname = buildOutputName(subdir, m) redoModule(m, fname, imported_module_names) From d72aa3f85f473da39ca574b89781e31fca47e413 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 17 Feb 2011 13:14:28 +0100 Subject: [PATCH 12/17] fix Python 3 incompatibility (PY-2955) --- python/helpers/generator3.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 0eb5ad7835b4..9ba4dd28160c 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -26,7 +26,7 @@ but seemingly no one uses them in C extensions yet anyway. from datetime import datetime -OUR_OWN_DATETIME = datetime(2011, 02, 13, 1, 55, 0) # datetime.now() of edit time +OUR_OWN_DATETIME = datetime(2011, 2, 13, 1, 55, 0) # datetime.now() of edit time # we could use script's ctime, but the actual running copy may have it all wrong. # # Note: DON'T FORGET TO UPDATE! From 651ad4358bd5e11a8225d7b7a4681bd60f0383a3 Mon Sep 17 00:00:00 2001 From: Dmitry Cheryasov Date: Thu, 17 Feb 2011 15:44:57 +0200 Subject: [PATCH 13/17] Fix multi-line import blunder --- python/helpers/generator3.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 9ba4dd28160c..79316f7346a5 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -26,7 +26,7 @@ but seemingly no one uses them in C extensions yet anyway. from datetime import datetime -OUR_OWN_DATETIME = datetime(2011, 2, 13, 1, 55, 0) # datetime.now() of edit time +OUR_OWN_DATETIME = datetime(2011, 2, 17, 15, 30, 0) # datetime.now() of edit time # we could use script's ctime, but the actual running copy may have it all wrong. # # Note: DON'T FORGET TO UPDATE! @@ -1922,7 +1922,7 @@ class ModuleRedeclarator(object): if names: self._defined[mod_name] = True right_pos = 0 # tracks width of list to fold it at right margin - import_heading = "from % s import " % mod_name + import_heading = "from % s import (" % mod_name right_pos += len(import_heading) names_pack = [import_heading] indent_level = 0 @@ -1939,10 +1939,15 @@ class ModuleRedeclarator(object): names_pack.append(n) names_pack.append(", ") right_pos += (len_n + 2) - if names_pack: # last line - self.imports_buf.out(indent_level, *names_pack[:-1]) # cut last comma + # last line is... + if indent_level == 0: # one line + names_pack[0] = names_pack[0][:-1] # cut off lpar + names_pack[-1] = "" # cut last comma + else: # last line of multiline + names_pack[-1] = ")" # last comma -> rpar + self.imports_buf.out(indent_level, *names_pack) - self.imports_buf.out(0, "") # empty line after group + self.imports_buf.out(0, "") # empty line after group def hasRegularPythonExt(name): From 314f2c10c989690199a6ece1a07c950a86ecbbfc Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 17 Feb 2011 17:24:06 +0300 Subject: [PATCH 14/17] Resolve fixed once more, to fix PY-2211 --- .../python/psi/resolve/ResolveImportUtil.java | 66 +++++++++++-------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java index d6faa25e90aa..0b5f154b246b 100644 --- a/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java +++ b/python/src/com/jetbrains/python/psi/resolve/ResolveImportUtil.java @@ -289,7 +289,8 @@ public class ResolveImportUtil { } } - List results = visitRoots(moduleQualifiedName, foothold); + List results = + visitRoots(moduleQualifiedName, foothold.getManager(), ModuleUtil.findModuleForPsiElement(foothold), foothold, true); if (cache != null) { cache.put(moduleQualifiedName, results); @@ -297,23 +298,35 @@ public class ResolveImportUtil { return results; } - private static List visitRoots(@NotNull PyQualifiedName moduleQualifiedName, @NotNull PsiElement foothold) { - PsiFile footholdFile = foothold.getContainingFile(); + private static List visitRoots(@NotNull PyQualifiedName moduleQualifiedName, + @NotNull PsiManager manager, + @Nullable Module module, + @Nullable PsiElement foothold, + boolean checkForPackage) { // resolve the name considering every source root as a package dir, as if it's a deployed package. django console does so. + PsiFile footholdFile = foothold != null ? foothold.getContainingFile() : null; boolean has_djando_facet = false; - final Module source_module = ModuleUtil.findModuleForPsiElement(foothold); - if (source_module != null) { - has_djando_facet = FacetManager.getInstance(source_module).getFacetByType(DjangoFacetType.ID) != null; + if (module != null) { + has_djando_facet = FacetManager.getInstance(module).getFacetByType(DjangoFacetType.ID) != null; } ResolveInRootVisitor visitor; if (has_djando_facet) { - visitor = new ResolveInRootAsTopPackageVisitor(moduleQualifiedName, foothold.getManager(), footholdFile, true); + visitor = new ResolveInRootAsTopPackageVisitor(moduleQualifiedName, manager, footholdFile, checkForPackage); } else { - visitor = new ResolveInRootVisitor(moduleQualifiedName, foothold.getManager(), footholdFile, true); + visitor = new ResolveInRootVisitor(moduleQualifiedName, manager, footholdFile, checkForPackage); + } + if (module != null) { + visitRoots(module, visitor); + return visitor.results; + } + else if (foothold != null) { + visitRoots(foothold, visitor); + return visitor.results; + } + else { + throw new IllegalStateException(); } - visitRoots(foothold, visitor); - return visitor.results; } @Nullable @@ -337,16 +350,12 @@ public class ResolveImportUtil { boolean checkForPackage) { PythonPathCache cache = PythonModulePathCache.getInstance(module); final List cachedResults = cache.get(moduleQualifiedName); - if (cachedResults != null) { - return cachedResults; - } - ResolveInRootVisitor visitor = new ResolveInRootVisitor(moduleQualifiedName, - PsiManager.getInstance(module.getProject()), - null, - checkForPackage); - visitRoots(module, visitor); - cache.put(moduleQualifiedName, visitor.results); - return visitor.results; + //if (cachedResults != null) { + // return cachedResults; + //} + List results = visitRoots(moduleQualifiedName, PsiManager.getInstance(module.getProject()), module, null, checkForPackage); + cache.put(moduleQualifiedName, results); + return results; } @NotNull @@ -431,7 +440,7 @@ public class ResolveImportUtil { } - public static void visitRoots(final PsiElement elt, @NotNull final RootVisitor visitor) { + public static void visitRoots(@NotNull final PsiElement elt, @NotNull final RootVisitor visitor) { // real search final Module module = ModuleUtil.findModuleForPsiElement(elt); if (module != null) { @@ -442,6 +451,14 @@ public class ResolveImportUtil { } } + private static void visitRoots(@NotNull Module module, RootVisitor visitor) { + // TODO: implement a proper module-like approach in PyCharm for "project's dirs on pythonpath", minding proper search order + // Module-based approach works only in the IDEA plugin. + if (visitModuleContentEntries(module, visitor)) return; + // else look in SDK roots + visitModuleSdkRoots(visitor, module); + } + private static void visitSdkRoots(PsiElement elt, RootVisitor visitor) { // no module, another way to look in SDK roots final PsiFile elt_psifile = elt.getContainingFile(); @@ -471,13 +488,6 @@ public class ResolveImportUtil { } } - private static void visitRoots(Module module, RootVisitor visitor) { - // TODO: implement a proper module-like approach in PyCharm for "project's dirs on pythonpath", minding proper search order - // Module-based approach works only in the IDEA plugin. - if (visitModuleContentEntries(module, visitor)) return; - // else look in SDK roots - visitModuleSdkRoots(visitor, module); - } private static boolean visitModuleContentEntries(Module module, RootVisitor visitor) { ModuleRootManager rootManager = ModuleRootManager.getInstance(module); From d5492e16c785e6a773b7e9f28097583155494dc2 Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Thu, 17 Feb 2011 19:41:30 +0300 Subject: [PATCH 15/17] Traceback collision fixed in one more place. --- python/helpers/pydev/pydevd_frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index cde182d957d3..ac3d8b3fd768 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -81,7 +81,7 @@ class PyDBFrame: line = frame.f_lineno if event == 'exception' and info.pydev_state != STATE_SUSPEND: #and breakpoint is not None: - (exception, value, traceback) = arg + (exception, value, trace) = arg global exception_set exception_breakpoint = get_exception_breakpoint(exception, tuple(exception_set), NOTIFY_ALWAYS) From 191a33e8397e0ace80a16185f0d4f971dfd428c0 Mon Sep 17 00:00:00 2001 From: nik Date: Thu, 17 Feb 2011 15:24:57 +0300 Subject: [PATCH 16/17] testFramework & junit exluded from classpath fo build_searchable_options task --- python/build/pycharm_build.gant | 2 -- 1 file changed, 2 deletions(-) diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index db83e79776d8..fca2805e8fa4 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -281,11 +281,9 @@ def build_searchable_options() { arg(line: "traverseUI ${dest_dir}/searchableOptions.xml") classpath() { - pathelement(location: "$ch/lib/junit.jar") project["python-ide"].runtimeClasspath().each { pathelement(location: it) } - pathelement(location: project.builder.moduleOutput(project["testFramework"])) // contains headless implementation classes } } } From 52174dc6512026db9fea387bd54643261f24a7f5 Mon Sep 17 00:00:00 2001 From: Alexey Kudravtsev Date: Thu, 17 Feb 2011 20:10:19 +0300 Subject: [PATCH 17/17] toPsiElementArray, toPsiFileArray --- .../codeInsight/editorActions/moveUpDown/StatementMover.java | 3 ++- python/src/com/jetbrains/python/psi/impl/PyClassImpl.java | 2 +- .../com/jetbrains/python/refactoring/PyRefactoringUtil.java | 2 +- .../python/refactoring/classes/PyClassRefactoringUtil.java | 3 ++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/StatementMover.java b/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/StatementMover.java index 785fbc0ff478..dc940d1a8b07 100644 --- a/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/StatementMover.java +++ b/python/src/com/jetbrains/python/codeInsight/editorActions/moveUpDown/StatementMover.java @@ -12,6 +12,7 @@ import com.intellij.openapi.util.Pair; import com.intellij.psi.*; import com.intellij.psi.impl.PsiDocumentManagerImpl; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilBase; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyPsiUtils; import org.jetbrains.annotations.NotNull; @@ -92,7 +93,7 @@ public class StatementMover extends LineMover { return PsiElement.EMPTY_ARRAY; } } - return array.toArray(new PsiElement[array.size()]); + return PsiUtilBase.toPsiElementArray(array); } private static boolean isNotValidStatementRange(Pair range) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 39160dd0ec30..c74ce30c4d9c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -137,7 +137,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement } } } - return superClasses.toArray(new PsiElement[superClasses.size()]); + return PsiUtilBase.toPsiElementArray(superClasses); } /* The implementation is manifestly lazy wrt psi scanning and uses stack rather sparingly. diff --git a/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java b/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java index 31a17a17b3f1..9f257b7e24ba 100644 --- a/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java +++ b/python/src/com/jetbrains/python/refactoring/PyRefactoringUtil.java @@ -234,7 +234,7 @@ public class PyRefactoringUtil { return PsiElement.EMPTY_ARRAY; } } - return array.toArray(new PsiElement[array.size()]); + return PsiUtilBase.toPsiElementArray(array); } private PyRefactoringUtil() { diff --git a/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java b/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java index 06d5ddc5f79b..37850992b79f 100644 --- a/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java +++ b/python/src/com/jetbrains/python/refactoring/classes/PyClassRefactoringUtil.java @@ -7,6 +7,7 @@ import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.util.PsiUtilBase; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.actions.AddImportHelper; import com.jetbrains.python.codeInsight.PyCodeInsightSettings; @@ -113,7 +114,7 @@ public class PyClassRefactoringUtil { for (PyElement element : elements) { final Set comments = PyUtil.getComments(element); if (comments.size() > 0) { - PyPsiUtils.removeElements(comments.toArray(new PsiElement[comments.size()])); + PyPsiUtils.removeElements(PsiUtilBase.toPsiElementArray(comments)); } } PyPsiUtils.removeElements(elements);