PY-14216 Code completion for Model.objects does not work with Django 1.7.x
authorIlya.Kazakevich <Ilya.Kazakevich@jetbrains.com>
Thu, 15 Jan 2015 12:41:20 +0000 (15:41 +0300)
committerIlya.Kazakevich <Ilya.Kazakevich@jetbrains.com>
Thu, 15 Jan 2015 12:41:20 +0000 (15:41 +0300)
PY-14714 Unresolved attribute reference 'objects' for class 'Foo'

DjangoTestCase now can use mock Django as well as real Python installation (see  DjangoEnvironmentProvider)

platform/testFramework/src/com/intellij/testFramework/fixtures/CodeInsightTestFixture.java
platform/testFramework/src/com/intellij/testFramework/fixtures/impl/CodeInsightTestFixtureImpl.java
python/testSrc/com/jetbrains/env/PyEnvTestCase.java
python/testSrc/com/jetbrains/python/PyBinaryModuleCompletionTest.java
python/testSrc/com/jetbrains/python/fixtures/PyLightProjectDescriptor.java [new file with mode: 0644]
python/testSrc/com/jetbrains/python/fixtures/PyTestCase.java

index 2cd323c0fa8fab6a3fbf19c0a6cc7934ddfdca83..61efedf49fc294d9202b3f1a351b3a5a715e37a7 100644 (file)
@@ -274,7 +274,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
    * @return duration
    */
   long checkHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings);
-  
+
   long checkHighlighting(boolean checkWarnings, boolean checkInfos, boolean checkWeakWarnings, boolean ignoreExtraHighlighting);
 
   long checkHighlighting();
@@ -356,7 +356,7 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
    *
    * @param hint the text that the intention text should begin with.
    * @return the matching intention
-   * @throws java.lang.AssertionError if no intentions are found or if multiple intentions match the hint text. 
+   * @throws java.lang.AssertionError if no intentions are found or if multiple intentions match the hint text.
    */
   IntentionAction findSingleIntention(@NotNull String hint);
 
@@ -561,9 +561,11 @@ public interface CodeInsightTestFixture extends IdeaProjectTestFixture {
    * Actually, it works just like {@link #completeBasic()} but supports
    * several  {@link #CARET_MARKER}
    *
+   * @return list of all completion elements just like in {@link #completeBasic()}
    * @see #completeBasic()
    */
-  void completeBasicAllCarets();
+  @NotNull
+  List<LookupElement> completeBasicAllCarets();
 
   void saveText(VirtualFile file, String text);
 }
index 7bcd62e9bceec9cf659a82f41b2f8dbaeb11e2e8..7c0d11761826859164839eb7024c5fb4d7a8f3ce 100644 (file)
@@ -1068,7 +1068,8 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
 
 
   @Override
-  public void completeBasicAllCarets() {
+  @NotNull
+  public final List<LookupElement> completeBasicAllCarets() {
     final CaretModel caretModel = myEditor.getCaretModel();
     final List<Caret> carets = caretModel.getAllCarets();
 
@@ -1082,10 +1083,15 @@ public class CodeInsightTestFixtureImpl extends BaseFixture implements CodeInsig
     // We do it in reverse order because completions would affect offsets
     // i.e.: when you complete "spa" to "spam", next caret offset increased by 1
     Collections.reverse(originalOffsets);
+    final List<LookupElement> result = new ArrayList<LookupElement>();
     for (final int originalOffset : originalOffsets) {
       caretModel.moveToOffset(originalOffset);
-      completeBasic();
+      final LookupElement[] lookupElements = completeBasic();
+      if (lookupElements != null) {
+        result.addAll(Arrays.asList(lookupElements));
+      }
     }
+    return result;
   }
 
   @Override
index 853a5504de63d3fc102758c295c032d0e4adc823..4907b1e27ddf5d4a4688b021d771de2afe901d2d 100644 (file)
@@ -1,13 +1,17 @@
 package com.jetbrains.env;
 
 import com.google.common.collect.Lists;
+import com.intellij.execution.ExecutionException;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.projectRoots.Sdk;
 import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.testFramework.UsefulTestCase;
 import com.intellij.util.SystemProperties;
 import com.intellij.util.ui.UIUtil;
 import com.jetbrains.python.fixtures.PyTestCase;
+import com.jetbrains.python.packaging.PyPackage;
+import com.jetbrains.python.packaging.PyPackageManager;
 import org.hamcrest.Matchers;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -57,6 +61,11 @@ public abstract class PyEnvTestCase extends UsefulTestCase {
     PyTestCase.initPlatformPrefix();
   }
 
+  @Nullable
+  public static PyPackage getInstalledDjango(@NotNull final Sdk sdk) throws ExecutionException {
+    return PyPackageManager.getInstance(sdk).findPackage("django", false);
+  }
+
   @Override
   public void setUp() throws Exception {
     super.setUp();
index 009212fee4bd225e755f7d62bada37573ae9961c..eb0b3ef56acf1e55048f65d04043c702fc9a5b21 100644 (file)
@@ -16,6 +16,7 @@
 package com.jetbrains.python;
 
 import com.intellij.testFramework.LightProjectDescriptor;
+import com.jetbrains.python.fixtures.PyLightProjectDescriptor;
 import com.jetbrains.python.fixtures.PyTestCase;
 
 /**
diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyLightProjectDescriptor.java b/python/testSrc/com/jetbrains/python/fixtures/PyLightProjectDescriptor.java
new file mode 100644 (file)
index 0000000..8569b2f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2015 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.jetbrains.python.fixtures;
+
+import com.intellij.openapi.application.PathManager;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.ContentEntry;
+import com.intellij.openapi.roots.ModifiableRootModel;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.roots.libraries.Library;
+import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.testFramework.LightProjectDescriptor;
+import com.jetbrains.python.PythonMockSdk;
+import com.jetbrains.python.PythonModuleTypeBase;
+
+/**
+ * Project descriptor (extracted from {@link com.jetbrains.python.fixtures.PyTestCase}) and should be used with it.
+ * @author Ilya.Kazakevich
+*/
+public class PyLightProjectDescriptor implements LightProjectDescriptor {
+  private final String myPythonVersion;
+
+  public PyLightProjectDescriptor(String pythonVersion) {
+    myPythonVersion = pythonVersion;
+  }
+
+  @Override
+  public ModuleType getModuleType() {
+    return PythonModuleTypeBase.getInstance();
+  }
+
+  @Override
+  public Sdk getSdk() {
+    return PythonMockSdk.findOrCreate(myPythonVersion);
+  }
+
+  @Override
+  public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
+  }
+
+  protected void createLibrary(ModifiableRootModel model, final String name, final String path) {
+    final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary(name).getModifiableModel();
+    final VirtualFile home =
+      LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManager.getHomePath() + path);
+
+    modifiableModel.addRoot(home, OrderRootType.CLASSES);
+    modifiableModel.commit();
+  }
+}
index af93b8178dca695674c1efaed8f0d26dbf71c90c..ddd200e071d072e142c8cdaf227c6f7a15ffabec 100644 (file)
@@ -28,19 +28,12 @@ import com.intellij.find.findUsages.FindUsagesOptions;
 import com.intellij.ide.DataManager;
 import com.intellij.openapi.actionSystem.DataContext;
 import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.application.PathManager;
 import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.ex.EditorEx;
 import com.intellij.openapi.extensions.Extensions;
 import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModuleType;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.roots.ContentEntry;
-import com.intellij.openapi.roots.ModifiableRootModel;
-import com.intellij.openapi.roots.OrderRootType;
 import com.intellij.openapi.roots.impl.FilePropertyPusher;
-import com.intellij.openapi.roots.libraries.Library;
 import com.intellij.openapi.util.Ref;
 import com.intellij.openapi.vfs.LocalFileSystem;
 import com.intellij.openapi.vfs.VirtualFile;
@@ -62,8 +55,6 @@ import com.intellij.usages.Usage;
 import com.intellij.usages.rules.PsiElementUsage;
 import com.intellij.util.CommonProcessors.CollectProcessor;
 import com.jetbrains.python.PythonHelpersLocator;
-import com.jetbrains.python.PythonMockSdk;
-import com.jetbrains.python.PythonModuleTypeBase;
 import com.jetbrains.python.PythonTestUtil;
 import com.jetbrains.python.psi.LanguageLevel;
 import com.jetbrains.python.psi.PyClass;
@@ -318,37 +309,6 @@ public abstract class PyTestCase extends UsefulTestCase {
     configurator.configureProject(myFixture.getProject(), newPath, moduleRef);
   }
 
-  protected static class PyLightProjectDescriptor implements LightProjectDescriptor {
-    private final String myPythonVersion;
-
-    public PyLightProjectDescriptor(String pythonVersion) {
-      myPythonVersion = pythonVersion;
-    }
-
-    @Override
-    public ModuleType getModuleType() {
-      return PythonModuleTypeBase.getInstance();
-    }
-
-    @Override
-    public Sdk getSdk() {
-      return PythonMockSdk.findOrCreate(myPythonVersion);
-    }
-
-    @Override
-    public void configureModule(Module module, ModifiableRootModel model, ContentEntry contentEntry) {
-    }
-
-    protected void createLibrary(ModifiableRootModel model, final String name, final String path) {
-      final Library.ModifiableModel modifiableModel = model.getModuleLibraryTable().createLibrary(name).getModifiableModel();
-      final VirtualFile home =
-        LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManager.getHomePath() + path);
-
-      modifiableModel.addRoot(home, OrderRootType.CLASSES);
-      modifiableModel.commit();
-    }
-  }
-
   public static void initPlatformPrefix() {
     PlatformTestCase.autodetectPlatformPrefix();
   }