diff --git a/python/build/pycharm_build.gant b/python/build/pycharm_build.gant index 87780f74d65f..c9ef216cb3a4 100644 --- a/python/build/pycharm_build.gant +++ b/python/build/pycharm_build.gant @@ -103,7 +103,7 @@ target('default': "Build artifacts") { def usedJars = buildModules(modules, ["python/lib", "plugins/coverage-common/lib"]) buildSearchableOptions("${projectBuilder.moduleOutput(findModule("platform-resources"))}/search", ["$home/build/idea.license", "$home/build/pycharm.license"], { - projectBuilder.moduleRuntimeClasspath(findModule("python-ide"), false).each { + projectBuilder.moduleRuntimeClasspath(findModule("main_pycharm"), false).each { pathelement(location: it) } }, "-Didea.platform.prefix=Python -Didea.no.jre.check=true") diff --git a/python/build/resources/logo.bmp b/python/build/resources/logo.bmp index 5ff00b6ed249..d696a6918464 100644 Binary files a/python/build/resources/logo.bmp and b/python/build/resources/logo.bmp differ diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index ec4879dfe850..4cbbb9bfd457 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -24,7 +24,7 @@ but seemingly no one uses them in C extensions yet anyway. # * re.search-bound, ~30% time, in likes of builtins and _gtk with complex docstrings. # None of this can seemingly be easily helped. Maybe there's a simpler and faster parser library? -VERSION = "1.123" # Must be a number-dot-number string, updated with each change that affects generated skeletons +VERSION = "1.124" # Must be a number-dot-number string, updated with each change that affects generated skeletons # Note: DON'T FORGET TO UPDATE! import sys @@ -1300,7 +1300,7 @@ class ModuleRedeclarator(object): if found_name: if found_name == as_name: notice = " # (!) real value is %r" % s - s = "object()" + s = "None" else: notice = " # (!) forward: %s, real value is %r" % (found_name, s) if SANE_REPR_RE.match(s): @@ -1308,7 +1308,7 @@ class ModuleRedeclarator(object): else: if not found_name: notice = " # (!) real value is %r" % s - out(indent, prefix, "object()", postfix, notice) + out(indent, prefix, "None", postfix, notice) def getRetType(self, s): @@ -2468,12 +2468,12 @@ if sys.platform == 'cli': def elapsed(self): return (DateTime.Now - self.started).TotalMilliseconds else: - from time import time + import time class Timer(object): def __init__(self): - self.started = time() + self.started = time.time() def elapsed(self): - return int((time() - self.started)*1000) + return int((time.time() - self.started)*1000) # command-line interface diff --git a/python/helpers/pydev/pydev_ipython_console.py b/python/helpers/pydev/pydev_ipython_console.py index 79f049129cf8..2175c02d2cca 100644 --- a/python/helpers/pydev/pydev_ipython_console.py +++ b/python/helpers/pydev/pydev_ipython_console.py @@ -12,15 +12,10 @@ os.environ['TERM'] = 'emacs' #to use proper page_more() for paging try: from pydev_ipython_console_010 import PyDevFrontEnd - - sys.stderr.write('PyDev console: using IPython 0.10\n') except: #IPython 0.11 broke compatibility... from pydev_ipython_console_011 import PyDevFrontEnd - sys.stderr.write('PyDev console: using IPython %s\n' % PyDevFrontEnd.version) - - #======================================================================================================================= # InterpreterInterface #======================================================================================================================= @@ -41,6 +36,9 @@ class InterpreterInterface(BaseInterpreterInterface): self.notify_about_magic() + def get_greeting_msg(self): + return self.interpreter.get_greeting_msg() + def doAddExec(self, line): self.notify_about_magic() if (line.rstrip().endswith('??')): diff --git a/python/helpers/pydev/pydev_ipython_console_010.py b/python/helpers/pydev/pydev_ipython_console_010.py index c3473fb7ad56..e093fefe9a32 100644 --- a/python/helpers/pydev/pydev_ipython_console_010.py +++ b/python/helpers/pydev/pydev_ipython_console_010.py @@ -124,3 +124,6 @@ class PyDevFrontEnd(PrefilterFrontEnd): else: return False + def get_greeting_msg(self): + return 'PyDev console: using IPython 0.10\n' + diff --git a/python/helpers/pydev/pydev_ipython_console_011.py b/python/helpers/pydev/pydev_ipython_console_011.py index 34227ce32f5d..da08bd136ab5 100644 --- a/python/helpers/pydev/pydev_ipython_console_011.py +++ b/python/helpers/pydev/pydev_ipython_console_011.py @@ -144,3 +144,6 @@ class PyDevFrontEnd: def is_automagic(self): return self.ipython.automagic + def get_greeting_msg(self): + return 'PyDev console: using IPython %s\n' % self.version + diff --git a/python/helpers/pydev/pydevconsole.py b/python/helpers/pydev/pydevconsole.py index fd2086b08d88..6789497bd87b 100644 --- a/python/helpers/pydev/pydevconsole.py +++ b/python/helpers/pydev/pydevconsole.py @@ -165,6 +165,9 @@ class InterpreterInterface(BaseInterpreterInterface): def close(self): sys.exit(0) + def get_greeting_msg(self): + return 'PyDev console: starting.\n' + def process_exec_queue(interpreter): while 1: @@ -277,6 +280,9 @@ def start_server(host, port, interpreter): print(port) print(client_port) + + sys.stderr.write(interpreter.get_greeting_msg()) + server.serve_forever() return server @@ -295,8 +301,6 @@ def StartServer(host, port, client_port): server_thread.setDaemon(True) server_thread.start() - if not IPYTHON: - sys.stderr.write('PyDev console: starting.\n') process_exec_queue(interpreter) diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index a7476580989c..28880d1a2b5b 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -1461,7 +1461,10 @@ if __name__ == '__main__': debugger = PyDB() if setup['save-signatures']: - debugger.signature_factory = SignatureFactory() + if pydevd_vm_type.GetVmType() == pydevd_vm_type.PydevdVmType.JYTHON: + sys.stderr.write("Collecting run-time type information is not supported for Jython\n") + else: + debugger.signature_factory = SignatureFactory() debugger.connect(host, port) diff --git a/python/helpers/pydev/pydevd_signature.py b/python/helpers/pydev/pydevd_signature.py index 6292360519ce..77559b35ae88 100644 --- a/python/helpers/pydev/pydevd_signature.py +++ b/python/helpers/pydev/pydevd_signature.py @@ -1,5 +1,6 @@ import inspect -from trace import modname +import trace +trace._warn = lambda *args: None # workaround for http://bugs.python.org/issue17143 (PY-8706) import gc from pydevd_comm import CMD_SIGNATURE_CALL_TRACE, NetCommand import pydevd_vars @@ -51,7 +52,7 @@ class SignatureFactory(object): code = frame.f_code filename = code.co_filename if filename: - modulename = modname(filename) + modulename = trace.modname(filename) else: modulename = None diff --git a/python/helpers/required_gen_version b/python/helpers/required_gen_version index ae5e26e48e1b..124263039ad3 100644 --- a/python/helpers/required_gen_version +++ b/python/helpers/required_gen_version @@ -6,7 +6,7 @@ (default) 1.92 # anything not explicitly marked -(built-in) 1.123 # skeletons of all built-in modules are built together +(built-in) 1.124 # skeletons of all built-in modules are built together # Note: modules like itertools, etc are "(built-in)" and are ignored if given separately _fileio 1.101 @@ -15,7 +15,7 @@ sys 1.101 thread 1.102 _thread 1.102 _struct 1.103 -datetime 1.121 +datetime 1.124 PyQt4.Qsci 1.94 PyQt4.QtAssistant 1.94 diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java index f86d08168b9a..d1667a07eed5 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaClassType.java @@ -12,6 +12,7 @@ import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -27,7 +28,7 @@ public class PyJavaClassType implements PyType { } @Nullable - public List resolveMember(final String name, + public List resolveMember(@NotNull final String name, PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java index a1c4d10ba3ac..977e7d2a3573 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaPackageType.java @@ -16,6 +16,7 @@ import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -34,7 +35,7 @@ public class PyJavaPackageType implements PyType { } @Override - public List resolveMember(String name, + public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { diff --git a/python/psi-api/resources/icons/com/jetbrains/python/pythonFile.png b/python/psi-api/resources/icons/com/jetbrains/python/pythonFile.png index 43aa9ef5f7d5..6d284ad8f77f 100644 Binary files a/python/psi-api/resources/icons/com/jetbrains/python/pythonFile.png and b/python/psi-api/resources/icons/com/jetbrains/python/pythonFile.png differ diff --git a/python/psi-api/resources/icons/com/jetbrains/python/pythonFile@2x.png b/python/psi-api/resources/icons/com/jetbrains/python/pythonFile@2x.png index efddd109f104..cbfcdf9b4030 100644 Binary files a/python/psi-api/resources/icons/com/jetbrains/python/pythonFile@2x.png and b/python/psi-api/resources/icons/com/jetbrains/python/pythonFile@2x.png differ diff --git a/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java b/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java index a7a87892fe77..3e5e117a30eb 100644 --- a/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java +++ b/python/psi-api/src/com/jetbrains/python/codeInsight/PyDynamicMember.java @@ -177,7 +177,7 @@ public class PyDynamicMember { myContext = context; } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { if (myTypeCallback != null) { return myTypeCallback.fun(myContext); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyParameter.java b/python/psi-api/src/com/jetbrains/python/psi/PyParameter.java index 123505596fca..a63d47be38f5 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyParameter.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyParameter.java @@ -26,4 +26,10 @@ public interface PyParameter extends PyElement { PyExpression getDefaultValue(); boolean hasDefaultValue(); + + /** + * @return true if the parameter is the 'self' parameter of an instance attribute function or a function + * annotated with @classmethod + */ + boolean isSelf(); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyTypedElement.java b/python/psi-api/src/com/jetbrains/python/psi/PyTypedElement.java index aedbf201152b..deeba1b60c19 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyTypedElement.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyTypedElement.java @@ -12,5 +12,5 @@ import org.jetbrains.annotations.Nullable; */ public interface PyTypedElement extends PyElement { @Nullable - PyType getType(@NotNull TypeEvalContext context); + PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key); } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java index fdbac85c3cf3..99075827ef97 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyType.java @@ -6,6 +6,7 @@ import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -31,7 +32,7 @@ public interface PyType { * or a list of elements that define the name, a la multiResolve(). */ @Nullable - List resolveMember(final String name, @Nullable PyExpression location, AccessDirection direction, + List resolveMember(@NotNull final String name, @Nullable PyExpression location, AccessDirection direction, PyResolveContext resolveContext); /** diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java index ed347a8183df..81988147bd01 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/PyTypeProviderBase.java @@ -37,7 +37,7 @@ public class PyTypeProviderBase implements PyTypeProvider { final ReturnTypeCallback typeCallback = myStringToReturnTypeMap.get(containingClass.getQualifiedName()); if (typeCallback != null) { final PyExpression qualifier = callSite != null ? callSite.getQualifier() : null; - PyType qualifierType = qualifier != null ? qualifier.getType(context) : null; + PyType qualifierType = qualifier != null ? context.getType(qualifier) : null; return typeCallback.getType(callSite, qualifierType, context); } } diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java index 36de8388619b..ea5844ecc62b 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java @@ -14,6 +14,12 @@ import java.util.*; * @author yole */ public class TypeEvalContext { + public static class Key { + private static final Key INSTANCE = new Key(); + + private Key() {} + } + private final boolean myAllowDataFlow; private final boolean myAllowStubToAST; private List myTrace; @@ -116,7 +122,7 @@ public class TypeEvalContext { } evaluating.add(element); try { - PyType result = element.getType(this); + PyType result = element.getType(this, Key.INSTANCE); if (result != null) { result.assertValid(element.toString()); } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PyPositionConverter.java b/python/pydevSrc/com/jetbrains/python/debugger/PyPositionConverter.java index 0b5098bfd3ef..2b44f9d9ff99 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PyPositionConverter.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PyPositionConverter.java @@ -15,5 +15,4 @@ public interface PyPositionConverter { @Nullable XSourcePosition convertFromPython(@NotNull final PySourcePosition position); - } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PySignature.java b/python/pydevSrc/com/jetbrains/python/debugger/PySignature.java index 6d1bd1b85037..a75887aba711 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PySignature.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PySignature.java @@ -1,13 +1,11 @@ package com.jetbrains.python.debugger; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.intellij.openapi.util.text.StringUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.Map; /** * @author traff @@ -17,7 +15,6 @@ public class PySignature { private final String myFunctionName; private final List myArgs = Lists.newArrayList(); - private final Map myTypeMap = Maps.newHashMap(); public PySignature(@NotNull String file, @NotNull String name) { myFile = file; @@ -25,8 +22,13 @@ public class PySignature { } @Nullable - public String getArgTypeQualifiedName(String name) { - return myTypeMap.get(name); + public String getArgTypeQualifiedName(@NotNull String name) { + for (NamedParameter param : myArgs) { + if (name.equals(param.getName())) { + return param.getTypeQualifiedName(); + } + } + return null; } @NotNull @@ -45,12 +47,15 @@ public class PySignature { } @NotNull - public PySignature merge(@NotNull PySignature signature) { + public PySignature addAllArgs(@NotNull PySignature signature) { for (NamedParameter param : signature.getArgs()) { NamedParameter ourParam = getArgForName(param.getName()); if (ourParam != null) { ourParam.addTypes(param.getTypesList()); } + else { + addArgument(param); + } } return this; } @@ -113,9 +118,13 @@ public class PySignature { } } - public PySignature addArgumentVar(String name, String type) { - myArgs.add(new NamedParameter(name, type)); - myTypeMap.put(name, type); + + public PySignature addArgument(String name, String type) { + return addArgument(new NamedParameter(name, type)); + } + + public PySignature addArgument(NamedParameter argument) { + myArgs.add(argument); return this; } } diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java index c32106bfdbdf..f487b4a3b218 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProtocolParser.java @@ -34,7 +34,7 @@ public class ProtocolParser { if (!"arg".equals(reader.getNodeName())) { throw new PyDebuggerException("Expected , found " + reader.getNodeName()); } - signature.addArgumentVar(readString(reader, "name", ""), readString(reader, "type", "")); + signature.addArgument(readString(reader, "name", ""), readString(reader, "type", "")); reader.moveUp(); } diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index bb1ec26f164d..60fda20373fa 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -192,8 +192,7 @@ INTN.doc.string.stub=Insert documentation string stub #SpecifyTypeInDocstringIntention INTN.specify.type=Specify type for reference in docstring INTN.specify.return.type=Specify return type in docstring -INTN.generate.docstring.with.types=Insert documentation string with types -INTN.add.types.to.docstring=Add dynamically inferred types to docstring +INTN.add.parameters.to.docstring=Add parameters to docstring #SpecifyTypeInPy3AnnotationsIntention INTN.specify.type.in.annotation=Specify type for reference using annotation diff --git a/python/src/com/jetbrains/python/codeInsight/PyDunderAllReference.java b/python/src/com/jetbrains/python/codeInsight/PyDunderAllReference.java index fc0b93b47984..eef673349ac0 100644 --- a/python/src/com/jetbrains/python/codeInsight/PyDunderAllReference.java +++ b/python/src/com/jetbrains/python/codeInsight/PyDunderAllReference.java @@ -19,7 +19,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * @author yole @@ -47,18 +49,24 @@ public class PyDunderAllReference extends PsiReferenceBase result = new ArrayList(); PyFile containingFile = (PyFile) getElement().getContainingFile().getOriginalFile(); final List dunderAll = containingFile.getDunderAll(); + final Set seenNames = new HashSet(); + if (dunderAll != null) { + seenNames.addAll(dunderAll); + } containingFile.processDeclarations(new PsiScopeProcessor() { @Override public boolean execute(@NotNull PsiElement element, ResolveState state) { if (element instanceof PsiNamedElement && !(element instanceof LightNamedElement)) { final String name = ((PsiNamedElement)element).getName(); - if (name != null && PyUtil.getInitialUnderscores(name) == 0 && (dunderAll == null || !dunderAll.contains(name))) { + if (name != null && PyUtil.getInitialUnderscores(name) == 0 && !seenNames.contains(name)) { + seenNames.add(name); result.add(LookupElementBuilder.create((PsiNamedElement) element).withIcon(element.getIcon(0))); } } else if (element instanceof PyImportElement) { final String visibleName = ((PyImportElement)element).getVisibleName(); - if (visibleName != null && (dunderAll == null || !dunderAll.contains(visibleName))) { + if (visibleName != null && !seenNames.contains(visibleName)) { + seenNames.add(visibleName); result.add(LookupElementBuilder.create(element, visibleName)); } } diff --git a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java index 27661b25a1d4..ee5c6a315ac8 100644 --- a/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java +++ b/python/src/com/jetbrains/python/codeInsight/completion/PyDictKeyNamesCompletionContributor.java @@ -115,7 +115,7 @@ public class PyDictKeyNamesCompletionContributor extends CompletionContributor { final String name = callee.getText(); if ("dict".equals(name)) { final TypeEvalContext context = TypeEvalContext.fast(); - final PyType type = dictConstructor.getType(context); + final PyType type = context.getType(dictConstructor); if (type != null && type.isBuiltin(context)) { final PyArgumentList list = dictConstructor.getArgumentList(); if (list == null) return; diff --git a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java index 375406fd68ed..3469eb7cd56e 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/AddImportHelper.java @@ -226,14 +226,17 @@ public class AddImportHelper { if (target instanceof PsiFileSystemItem && qName.getComponentCount() == 1) { addImportStatement(file, path, null, priority); } - else if (useQualified) { - addImportStatement(file, path, null, priority); - final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(file.getProject()); - element.replace(elementGenerator.createExpressionFromText(LanguageLevel.forElement(target), qName + "." + target.getName())); - } else { final PyQualifiedName toImportQName = QualifiedNameFinder.findCanonicalImportPath(toImport, element); - addImportFrom(file, null, toImportQName.toString(), target.getName(), null, priority); + if (useQualified) { + addImportStatement(file, path, null, priority); + final PyElementGenerator elementGenerator = PyElementGenerator.getInstance(file.getProject()); + final String targetName = PyUtil.getElementNameWithoutExtension(target); + element.replace(elementGenerator.createExpressionFromText(LanguageLevel.forElement(target), toImportQName + "." + targetName)); + } + else { + addImportFrom(file, null, toImportQName.toString(), target.getName(), null, priority); + } } } diff --git a/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java b/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java index fb639a875289..dd6ca8c68616 100644 --- a/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java +++ b/python/src/com/jetbrains/python/codeInsight/imports/ImportFromExistingAction.java @@ -135,7 +135,11 @@ public class ImportFromExistingAction implements QuestionAction { else { String qualifiedName = item.getPath().toString(); if (myUseQualifiedImport) { - AddImportHelper.addImportStatement(file, qualifiedName, null, priority); + String nameToImport = qualifiedName; + if (item.getImportable() instanceof PsiFileSystemItem) { + nameToImport += "." + myName; + } + AddImportHelper.addImportStatement(file, nameToImport, null, priority); myTarget.replace(gen.createExpressionFromText(LanguageLevel.forElement(myTarget), qualifiedName + "." + myName)); } else { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java index 875ca8ed89bd..bb881905c74b 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java @@ -141,7 +141,7 @@ public class ImportFromToImportIntention implements IntentionAction { PyReferenceExpression ref = import_element.getImportReferenceExpression(); if (ref != null && ref.isValid()) { PsiElement target = ref.getReference().resolve(); - if (target instanceof PyExpression && ((PyExpression)target).getType(TypeEvalContext.fast()) instanceof PyModuleType) return false; + if (target instanceof PyExpression && TypeEvalContext.fast().getType((PyExpression)target) instanceof PyModuleType) return false; } } diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java index 7bacf03016af..34634a3e03f3 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java @@ -38,7 +38,7 @@ public class PyDictConstructorToLiteralFormIntention extends BaseIntentionAction if (expression != null && expression.isCalleeText("dict")) { final TypeEvalContext context = TypeEvalContext.fast(); - PyType type = expression.getType(context); + PyType type = context.getType(expression); if (type != null && type.isBuiltin(context)) { PyExpression[] argumentList = expression.getArguments(); for (PyExpression argument : argumentList) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java index b0620d75658e..89259692943b 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java @@ -12,9 +12,7 @@ import com.jetbrains.python.PyBundle; import com.jetbrains.python.debugger.PySignature; import com.jetbrains.python.debugger.PySignatureCacheManager; import com.jetbrains.python.documentation.PyDocstringGenerator; -import com.jetbrains.python.documentation.PythonDocumentationProvider; import com.jetbrains.python.psi.PyFunction; -import com.jetbrains.python.psi.PyStatementList; import com.jetbrains.python.psi.PyUtil; import org.jetbrains.annotations.NotNull; @@ -24,7 +22,7 @@ import org.jetbrains.annotations.NotNull; * (with checked format) */ public class PyGenerateDocstringIntention extends BaseIntentionAction { - private String myText = PyBundle.message("INTN.doc.string.stub"); + private String myText; @NotNull public String getFamilyName() { @@ -46,45 +44,29 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction { if (function == null) { return false; } - return isAvailableForFunction(project, elementAt, function); + return isAvailableForFunction(project, function); } - private boolean isAvailableForFunction(Project project, PsiElement elementAt, PyFunction function) { - PySignature signature = PySignatureCacheManager.getInstance(project).findSignature(function); - if (signature != null) { - if (function.getDocStringValue() != null) { - PyDocstringGenerator docstringGenerator = new PyDocstringGenerator(function); - addFunctionArguments(function, signature, docstringGenerator); + private boolean isAvailableForFunction(Project project, PyFunction function) { + if (function.getDocStringValue() != null) { + PySignature signature = PySignatureCacheManager.getInstance(project).findSignature(function); + + PyDocstringGenerator docstringGenerator = new PyDocstringGenerator(function); + + docstringGenerator.addFunctionArguments(function, signature); - if (docstringGenerator.haveParametersToAdd()) { - myText = PyBundle.message("INTN.add.types.to.docstring"); - return true; - } + if (docstringGenerator.haveParametersToAdd()) { + myText = PyBundle.message("INTN.add.parameters.to.docstring"); + return true; } else { - myText = PyBundle.message("INTN.generate.docstring.with.types"); - return true; - } - } - - PyStatementList list = PsiTreeUtil.getParentOfType(elementAt, PyStatementList.class, - false, PyFunction.class); - if (list == null) { - if (function.getDocStringExpression() != null) { return false; } - final PyStatementList statementList = function.getStatementList(); - if (statementList != null && statementList.getStatements().length != 0) { - return true; - } } - return false; - } - - private static void addFunctionArguments(PyFunction function, PySignature signature, PyDocstringGenerator docstringGenerator) { - for (PySignature.NamedParameter param : signature.getArgs()) { - docstringGenerator.withParamTypedByQualifiedName("type", param.getName(), param.getTypeQualifiedName(), function); + else { + myText = PyBundle.message("INTN.doc.string.stub"); + return true; } } @@ -108,14 +90,11 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction { PySignature signature = PySignatureCacheManager.getInstance(project).findSignature(function); - if (signature != null) { - - addFunctionArguments(function, signature, docstringGenerator); - - docstringGenerator.build(); - } - else { - PythonDocumentationProvider.insertDocStub(function, project, editor); + docstringGenerator.addFunctionArguments(function, signature); + if (function.getDocStringValue() == null) { + docstringGenerator.withReturn(); } + + docstringGenerator.build(); } } diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java index b57ea1d698f2..690207bcb9f5 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java @@ -62,7 +62,7 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction } if (expression instanceof PyStringLiteralExpression) continue; - final PyType type = expression.getType(TypeEvalContext.fastStubOnly(file)); + final PyType type = TypeEvalContext.fastStubOnly(file).getType(expression); final boolean isStringReference = PyTypeChecker.match(cache.getStringType(LanguageLevel.forElement(expression)), type, TypeEvalContext.fastStubOnly(file)) && type != null; if (!isStringReference) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java index e4f2d377c9cf..2523c8328778 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java @@ -37,21 +37,22 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention { public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset()); PyExpression problemElement = getProblemElement(elementAt); - PsiReference reference = problemElement == null? null : problemElement.getReference(); + PsiReference reference = problemElement == null ? null : problemElement.getReference(); - final PsiElement resolved = reference != null? reference.resolve() : null; + final PsiElement resolved = reference != null ? reference.resolve() : null; PyParameter parameter = getParameter(problemElement, resolved); - String kind = parameter != null? "type" : "rtype"; + String kind = parameter != null ? "type" : "rtype"; final Callable callable = getCallable(elementAt); - if (callable instanceof PyFunction) + if (callable instanceof PyFunction) { generateDocstring(kind, (PyFunction)callable, problemElement); + } } private static void generateDocstring(String kind, PyFunction pyFunction, PyExpression problemElement) { - String name = "rtype".equals(kind)? "" : StringUtil.notNullize(problemElement.getName()); + String name = "rtype".equals(kind) ? "" : StringUtil.notNullize(problemElement.getName()); PyDocstringGenerator docstringGenerator = new PyDocstringGenerator(pyFunction); @@ -69,7 +70,7 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention { @Override protected void updateText(boolean isReturn) { - myText = isReturn? PyBundle.message("INTN.specify.return.type") : PyBundle.message("INTN.specify.type"); + myText = isReturn ? PyBundle.message("INTN.specify.return.type") : PyBundle.message("INTN.specify.type"); } @Override diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java index 324cbca8b755..1dc1d8ca8309 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java @@ -59,7 +59,7 @@ public class TypeAssertionIntention implements IntentionAction { (reference != null && reference.resolve() == null)) { return false; } - final PyType type = problemElement.getType(TypeEvalContext.fastStubOnly(file)); + final PyType type = TypeEvalContext.fastStubOnly(file).getType(problemElement); return (type == null || type instanceof PyReturnTypeReference); } diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index 2faf7928d249..2c824e67048d 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -38,7 +38,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType } @Override - public List resolveMember(String name, + public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index da7968059431..9802764908e4 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -156,12 +156,12 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { if ("contextlib.closing".equals(contextManager.getQualifiedName()) && withExpression instanceof PyCallExpression) { PyExpression closee = ((PyCallExpression)withExpression).getArgument(0, PyExpression.class); if (closee != null) { - return closee.getType(context); + return context.getType(closee); } } final String name = contextManager.getName(); if ("FileIO".equals(name) || "TextIOWrapper".equals(name) || "IOBase".equals(name) || "_IOBase".equals(name)) { - return withExpression.getType(context); + return context.getType(withExpression); } return null; } @@ -191,7 +191,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { if (p.isPositionalContainer() || p.isKeywordContainer() || name == null) { continue; } - final PyType argType = entry.getKey().getType(context); + final PyType argType = context.getType(entry.getKey()); final PyType paramType = getParameterTypeByQName(overloadedQName, name, anchor); if (PyTypeChecker.match(paramType, argType, context)) { if (paramType != null && !PyTypeChecker.isUnknown(argType)) { diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index 787e27f44b36..2748b24664fe 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -250,6 +250,11 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr @Override public void recordSignature(PySignature signature) { + if (myPositionConverter instanceof PyRemotePositionConverter) { + String localPath = ((PyRemotePositionConverter)myPositionConverter).getPathMappingSettings().convertToLocal(signature.getFile()); + signature = new PySignature(localPath, signature.getFunctionName()).addAllArgs(signature); + } + PySignatureCacheManager.getInstance(getSession().getProject()).recordSignature(signature); } @@ -612,8 +617,8 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr if (myProcessHandler instanceof PythonProcessHandler) { ((PythonProcessHandler)myProcessHandler) .setShouldTryToKillSoftly(false); //while process is suspended it can't terminate softly, - //multiple processes in debug mode also can not terminate properly - //so its better to kill all the tree in a hard way + //multiple processes in debug mode also can not terminate properly + //so its better to kill all the tree in a hard way } } diff --git a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java index 0325dc661c08..2876b5a459b1 100644 --- a/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java +++ b/python/src/com/jetbrains/python/debugger/PySignatureCacheManagerImpl.java @@ -1,5 +1,8 @@ package com.jetbrains.python.debugger; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.Lists; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressManager; @@ -13,7 +16,8 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.newvfs.FileAttribute; import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.search.ProjectScopeBuilder; +import com.intellij.psi.search.ProjectScope; +import com.intellij.util.ArrayUtil; import com.jetbrains.django.util.VirtualFileUtil; import com.jetbrains.python.psi.PyClass; import com.jetbrains.python.psi.PyFunction; @@ -22,6 +26,8 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; /** * @author traff @@ -35,13 +41,24 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { private final Project myProject; + private final LoadingCache mySignatureCache = CacheBuilder.newBuilder() + .maximumSize(1000) + .expireAfterAccess(10, TimeUnit.MINUTES) + .build( + new CacheLoader() { + @Override + public String load(VirtualFile key) throws Exception { + return readAttributeFromFile(key); + } + }); + public PySignatureCacheManagerImpl(Project project) { myProject = project; } @Override public void recordSignature(@NotNull PySignature signature) { - GlobalSearchScope scope = ProjectScopeBuilder.getInstance(myProject).buildProjectScope(); + GlobalSearchScope scope = ProjectScope.getProjectScope(myProject); VirtualFile file = getFile(signature); if (file != null && scope.contains(file)) { @@ -49,21 +66,15 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { } } - private static void recordSignature(VirtualFile file, PySignature signature) { - byte[] data; - try { - data = CALL_SIGNATURES_ATTRIBUTE.readAttributeBytes(file); - } - catch (Exception e) { - data = null; - } + private void recordSignature(VirtualFile file, PySignature signature) { + String dataString = readAttribute(file); String[] lines; - if (data != null) { - lines = (new String(data)).split("\n"); + if (dataString != null) { + lines = dataString.split("\n"); } else { - lines = new String[0]; + lines = ArrayUtil.EMPTY_STRING_ARRAY; } boolean found = false; @@ -78,7 +89,7 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { else { //noinspection ConstantConditions lines[i] = signatureToString(stringToSignature(file. - getCanonicalPath(), lines[i]).merge(signature)); + getCanonicalPath(), lines[i]).addAllArgs(signature)); } } i++; @@ -96,7 +107,15 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { writeAttribute(file, attrString); } - private static void writeAttribute(@NotNull VirtualFile file, @NotNull String attrString) { + private void writeAttribute(@NotNull VirtualFile file, @NotNull String attrString) { + String cachedValue = mySignatureCache.asMap().get(file); + if (!attrString.equals(cachedValue)) { + mySignatureCache.put(file, attrString); + writeAttributeToAFile(file, attrString); + } + } + + private static void writeAttributeToAFile(@NotNull VirtualFile file, @NotNull String attrString) { try { CALL_SIGNATURES_ATTRIBUTE.writeAttributeBytes(file, attrString.getBytes()); } @@ -153,7 +172,7 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { } @Nullable - private static PySignature readSignatureAttributeFromFile(@NotNull VirtualFile file, @NotNull String name) { + private PySignature readSignatureAttributeFromFile(@NotNull VirtualFile file, @NotNull String name) { String content = readAttribute(file); if (content != null) { @@ -170,7 +189,21 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { } @Nullable - private static String readAttribute(VirtualFile file) { + private String readAttribute(@NotNull VirtualFile file) { + try { + String attrContent = mySignatureCache.get(file); + if (!StringUtil.isEmpty(attrContent)) { + return attrContent; + } + } + catch (ExecutionException e) { + //pass + } + return null; + } + + @NotNull + private static String readAttributeFromFile(@NotNull VirtualFile file) { byte[] data; try { data = CALL_SIGNATURES_ATTRIBUTE.readAttributeBytes(file); @@ -186,7 +219,7 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { else { content = null; } - return content; + return content != null ? content : ""; } @@ -198,7 +231,7 @@ public class PySignatureCacheManagerImpl extends PySignatureCacheManager { for (int i = 1; i < parts.length; i++) { String[] var = parts[i].split(":"); if (var.length == 2) { - signature = signature.addArgumentVar(var[0], var[1]); + signature = signature.addArgument(var[0], var[1]); } else { throw new IllegalStateException("Should be : format. " + parts[i] + " instead."); diff --git a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java index c005ced7c2b8..722d8e8168cc 100644 --- a/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java +++ b/python/src/com/jetbrains/python/documentation/DocStringTypeReference.java @@ -113,7 +113,7 @@ public class DocStringTypeReference extends PsiPolyVariantReferenceBase> myParamTypesOffset = Maps.newHashMap(); private PsiFile myFile; + private boolean myGenerateReturn; public PyDocstringGenerator(@NotNull PyDocStringOwner docStringOwner) { myDocStringOwner = docStringOwner; @@ -60,6 +62,25 @@ public class PyDocstringGenerator { myFile = myDocStringOwner.getContainingFile(); } + public void addFunctionArguments(@NotNull PyFunction function, + @Nullable PySignature signature) { + for (PyParameter functionParam : function.getParameterList().getParameters()) { + String paramName = functionParam.getName(); + if (!functionParam.isSelf() && !StringUtil.isEmpty(paramName)) { + assert paramName != null; + + String type = signature != null ? signature.getArgTypeQualifiedName(paramName) : null; + + if (type != null) { + withParamTypedByQualifiedName("type", paramName, type, function); + } + else { + withParam("param", paramName); + } + } + } + } + public PyDocstringGenerator withParam(@NotNull String kind, @NotNull String name) { return withParamTypedByName(kind, name, null); } @@ -74,6 +95,10 @@ public class PyDocstringGenerator { return this; } + public void withReturn() { + myGenerateReturn = true; + } + private PsiFile getFile() { return myFile; } @@ -140,7 +165,7 @@ public class PyDocstringGenerator { private Collection collectParametersToAdd() { String text = getDocstringText(); - StructuredDocString structuredDocString = StructuredDocString.parse(text); + StructuredDocString structuredDocString = StructuredDocString.parse(text); //TODO: do we need to cache it? return getParamsToAdd(structuredDocString, myParams); } @@ -214,14 +239,14 @@ public class PyDocstringGenerator { if (replacementText.length() > 0) { replacementText.deleteCharAt(replacementText.length() - 1); } + // if creating a new docstring, leave blank line where text will be entered + if (!StringUtil.containsAlphaCharacters(replacementText.toString())) { + replacementText.append("\n"); + } replacementText.append(ws); int i = 0; - if (paramsToAdd.size() == 0) { - throw new IllegalArgumentException("At least one parameter should be added"); - } - for (DocstringParam param : paramsToAdd) { replacementText.append(getPrefix()); replacementText.append(param.getKind()); @@ -241,6 +266,14 @@ public class PyDocstringGenerator { } } + if (myGenerateReturn && myDocStringOwner instanceof PyFunction) { + PyFunction function = (PyFunction)myDocStringOwner; + String returnType = PythonDocumentationProvider.generateRaiseOrReturn(function, " ", getPrefix(), true); + if (!returnType.isEmpty()) { + replacementText.append(ws).append(returnType); + } + } + int offset = replacementText.length(); if (addWS) { replacementText.append(ws); diff --git a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java index 5e93ad07fd1d..a29cf85622cf 100644 --- a/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyDocumentationBuilder.java @@ -79,7 +79,7 @@ class PyDocumentationBuilder { if (outer instanceof PyQualifiedExpression) { PyExpression qual = ((PyQualifiedExpression)outer).getQualifier(); if (qual != null) { - PyType type = qual.getType(TypeEvalContext.fast()); + PyType type = TypeEvalContext.fast().getType(qual); if (type instanceof PyClassType) { cls = ((PyClassType)type).getPyClass(); Property property = cls.findProperty(elementName); @@ -188,7 +188,7 @@ class PyDocumentationBuilder { boolean typeFromDocstringAdded = addTypeAndDescriptionFromDocstring((PyNamedParameter)followed); if (outer instanceof PyExpression) { TypeEvalContext context = TypeEvalContext.slow(); - PyType type = ((PyExpression)outer).getType(context); + PyType type = context.getType((PyExpression)outer); if (type != null) { String s = null; if (type instanceof PyDynamicallyEvaluatedType) { diff --git a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java index 02ff29ba919d..6ed09d702ffc 100644 --- a/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java +++ b/python/src/com/jetbrains/python/documentation/PyTypeModelBuilder.java @@ -187,7 +187,7 @@ public class PyTypeModelBuilder { if (np != null) { TypeModel paramType = _(UNKNOWN); - final PyType t = np.getType(myContext); + final PyType t = myContext.getType(np); if (t != null) { paramType = build(t, true); } diff --git a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java index d88d1083f26d..d691fcc80fd0 100644 --- a/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java +++ b/python/src/com/jetbrains/python/documentation/PythonDocumentationProvider.java @@ -149,7 +149,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i static String describeExpressionType(PyExpression expr) { final TypeEvalContext context = TypeEvalContext.slow(); - return String.format("Inferred type: %s", getTypeName(expr.getType(context), context)); + return String.format("Inferred type: %s", getTypeName(context.getType(expr), context)); } public static String getTypeDescription(@NotNull PyFunction fun) { @@ -177,7 +177,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i public static void describeExpressionTypeWithLinks(ChainIterable body, PyReferenceExpression expression, @NotNull TypeEvalContext context) { - PyType type = expression.getType(context); + PyType type = context.getType(expression); describeTypeWithLinks(body, expression, type, context); } @@ -481,7 +481,7 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i @Nullable private static PyClass inferClassOfParameter(PsiElement context) { if (context instanceof PyNamedParameter) { - final PyType type = ((PyNamedParameter)context).getType(TypeEvalContext.fast()); + final PyType type = TypeEvalContext.fast().getType((PyNamedParameter)context); if (type instanceof PyClassType) { return ((PyClassType)type).getPyClass(); } @@ -567,6 +567,12 @@ public class PythonDocumentationProvider extends AbstractDocumentationProvider i builder.append(offset); } } + builder.append(generateRaiseOrReturn(element, offset, prefix, checkReturn)); + return builder.toString(); + } + + public static String generateRaiseOrReturn(PyFunction element, String offset, String prefix, boolean checkReturn) { + StringBuilder builder = new StringBuilder(); if (checkReturn) { RaiseVisitor visitor = new RaiseVisitor(); PyStatementList statementList = element.getStatementList(); diff --git a/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java b/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java index 6314e6848bf3..8c3f64cd78c6 100644 --- a/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java +++ b/python/src/com/jetbrains/python/findUsages/PyUsageTypeProvider.java @@ -39,7 +39,7 @@ public class PyUsageTypeProvider implements UsageTypeProviderEx { if (element instanceof PyQualifiedExpression) { final PyExpression qualifier = ((PyQualifiedExpression)element).getQualifier(); if (qualifier != null) { - final PyType type = qualifier.getType(TypeEvalContext.fast()); + final PyType type = TypeEvalContext.fast().getType(qualifier); if (type == null || type instanceof PyTypeReference) { final PyCallExpression call = PsiTreeUtil.getParentOfType(element, PyCallExpression.class); if (call != null && element == call.getCallee()) { diff --git a/python/src/com/jetbrains/python/formatter/PyBlock.java b/python/src/com/jetbrains/python/formatter/PyBlock.java index 9a79e0a00565..5f9cd0d0f834 100644 --- a/python/src/com/jetbrains/python/formatter/PyBlock.java +++ b/python/src/com/jetbrains/python/formatter/PyBlock.java @@ -242,7 +242,8 @@ public class PyBlock implements ASTBlock { } private boolean isInControlStatement() { - return PsiTreeUtil.getParentOfType(_node.getPsi(), PyStatementPart.class, false, PyStatementList.class) != null; + return PsiTreeUtil.getParentOfType(_node.getPsi(), PyStatementPart.class, false, PyStatementList.class) != null || + PsiTreeUtil.getParentOfType(_node.getPsi(), PyWithItem.class) != null; } private boolean isSliceOperand(ASTNode child) { diff --git a/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java b/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java index 323730bcbb25..6e139c1e1d80 100644 --- a/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyAugmentAssignmentInspection.java @@ -75,7 +75,7 @@ public class PyAugmentAssignmentInspection extends PyInspection { registerProblem(node, "Assignment can be replaced with augmented assignment", quickFix); } else { - final PyType type = rightExpression.getType(myTypeEvalContext); + final PyType type = myTypeEvalContext.getType(rightExpression); if (type != null) { final PyBuiltinCache cache = PyBuiltinCache.getInstance(rightExpression); if (PyTypeChecker.match(cache.getComplexType(), type, myTypeEvalContext) || diff --git a/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java b/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java index 33d60b068516..42cf00554ddb 100644 --- a/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyBroadExceptionInspection.java @@ -38,7 +38,7 @@ public class PyBroadExceptionInspection extends PyInspection { } public static boolean equalsException(@NotNull PyClass cls, @NotNull TypeEvalContext context) { - final PyType type = cls.getType(context); + final PyType type = context.getType(cls); return "Exception".equals(cls.getName()) && type != null && type.isBuiltin(context); } @@ -56,7 +56,7 @@ public class PyBroadExceptionInspection extends PyInspection { registerProblem(node.getFirstChild(), "Too broad exception clause"); } if (exceptClass != null) { - final PyType type = exceptClass.getType(myTypeEvalContext); + final PyType type = myTypeEvalContext.getType(exceptClass); if (type instanceof PyClassType) { final PyClass cls = ((PyClassType)type).getPyClass(); final PyExpression target = node.getTarget(); diff --git a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java index 366b9d075cc9..dfaabb94bd98 100644 --- a/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyCallingNonCallableInspection.java @@ -58,7 +58,7 @@ public class PyCallingNonCallableInspection extends PyInspection { return; } if (!callable) { - final PyType calleeType = callee != null ? callee.getType(myTypeEvalContext) : type; + final PyType calleeType = callee != null ? myTypeEvalContext.getType(callee) : type; if (calleeType instanceof PyClassType) { registerProblem(node, String.format("'%s' object is not callable", calleeType.getName())); } @@ -77,6 +77,6 @@ public class PyCallingNonCallableInspection extends PyInspection { if (element instanceof PyQualifiedExpression && PyNames.CLASS.equals(element.getName())) { return true; } - return PyTypeChecker.isCallable(element.getType(context)); + return PyTypeChecker.isCallable(context.getType(element)); } } diff --git a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java index 4e751db39380..d46900231ca2 100644 --- a/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyPropertyDefinitionInspection.java @@ -171,7 +171,7 @@ public class PyPropertyDefinitionInspection extends PyInspection { return; } if (resolved instanceof PyTypedElement) { - final PyType type = ((PyTypedElement)resolved).getType(myTypeEvalContext); + final PyType type = myTypeEvalContext.getType((PyTypedElement)resolved); final Boolean isCallable = PyTypeChecker.isCallable(type); if (isCallable != null && !isCallable) { registerProblem(element, PyBundle.message("INSP.strange.arg.want.callable")); diff --git a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java index 17638d594639..b7c46583b787 100644 --- a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java @@ -182,7 +182,7 @@ public class PyStringFormatInspection extends PyInspection { } } else if (rightExpression instanceof PySliceExpression && s != null) { - final PyType type = ((PySliceExpression)rightExpression).getOperand().getType(myTypeEvalContext); + final PyType type = myTypeEvalContext.getType(((PySliceExpression)rightExpression).getOperand()); if (type == null || "list".equals(type.getName()) || "str".equals(type.getName())) { checkTypeCompatible(problemTarget, builtinCache.getStrType(), PyTypeParser.getTypeByName(problemTarget, s)); diff --git a/python/src/com/jetbrains/python/inspections/PySuperArgumentsInspection.java b/python/src/com/jetbrains/python/inspections/PySuperArgumentsInspection.java index 809ce6001739..f51a570e081b 100644 --- a/python/src/com/jetbrains/python/inspections/PySuperArgumentsInspection.java +++ b/python/src/com/jetbrains/python/inspections/PySuperArgumentsInspection.java @@ -70,7 +70,7 @@ public class PySuperArgumentsInspection extends PyInspection { PyClass firstClass = null; if (firstElement instanceof PyClass) firstClass = (PyClass)firstElement; else if (firstElement instanceof PyExpression) { - PyType first_type = ((PyExpression)firstElement).getType(myTypeEvalContext); + PyType first_type = myTypeEvalContext.getType((PyExpression)firstElement); if (first_type instanceof PyClassType) { firstClass = ((PyClassType)first_type).getPyClass(); } diff --git a/python/src/com/jetbrains/python/inspections/PyTupleAssignmentBalanceInspection.java b/python/src/com/jetbrains/python/inspections/PyTupleAssignmentBalanceInspection.java index 9ca11ac7b5c9..c024638cd615 100644 --- a/python/src/com/jetbrains/python/inspections/PyTupleAssignmentBalanceInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTupleAssignmentBalanceInspection.java @@ -45,7 +45,7 @@ public class PyTupleAssignmentBalanceInspection extends PyInspection { lhsExpression = ((PyParenthesizedExpression)lhsExpression).getContainedExpression(); if (assignedValue == null) return; - PyType type = assignedValue.getType(myTypeEvalContext); + PyType type = myTypeEvalContext.getType(assignedValue); if (assignedValue instanceof PyReferenceExpression && !(type instanceof PyTupleType)) return; if (lhsExpression instanceof PyTupleExpression && type != null && !(type instanceof PyReturnTypeReference)){ int valuesLength = PyUtil.getElementsCount(assignedValue, myTypeEvalContext); diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index 8be02c241f58..5b51beb6b42a 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -71,8 +71,8 @@ public class PyTypeCheckerInspection extends PyInspection { // TODO: Support *args, **kwargs continue; } - final PyType argType = entry.getKey().getType(myTypeEvalContext); - final PyType paramType = p.getType(myTypeEvalContext); + final PyType argType = myTypeEvalContext.getType(entry.getKey()); + final PyType paramType = myTypeEvalContext.getType(p); checkTypes(paramType, argType, entry.getKey(), myTypeEvalContext, substitutions); } } diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 434093821767..715e6de3e73b 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -574,7 +574,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (reference instanceof PyOperatorReference && element instanceof PyQualifiedExpression) { final PyExpression receiver = ((PyOperatorReference)reference).getReceiver(); if (receiver != null) { - final PyType type = receiver.getType(context); + final PyType type = context.getType(receiver); if (type instanceof PyClassType) { final String name = ((PyClassType)type).getClassQName(); if (name != null) { @@ -589,7 +589,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { final String exprName = expr.getName(); if (exprName != null) { if (qualifier != null) { - final PyType type = qualifier.getType(context); + final PyType type = context.getType(qualifier); if (type instanceof PyClassType) { final String name = ((PyClassType)type).getClassQName(); if (name != null) { @@ -810,7 +810,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { @Nullable private static PsiElement resolveClassMember(@NotNull PyClass cls, @NotNull String name) { final TypeEvalContext context = TypeEvalContext.fastStubOnly(null); - final PyType type = cls.getType(context); + final PyType type = context.getType(cls); if (type != null) { final List results = type.resolveMember(name, null, AccessDirection.READ, PyResolveContext.noImplicits().withTypeEvalContext(context)); diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java index 1454a9c19f42..5aae8e6ec16b 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java @@ -247,15 +247,9 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { ? (PyNamedParameter) element : (PyNamedParameter) element.getParent(); name = namedParameter.getName(); - if (PsiTreeUtil.getParentOfType(element, PyClass.class) != null) { - // When function is inside a class, first parameter may be either self or cls which is always 'used'. - final PyFunction method = PsiTreeUtil.getParentOfType(element, PyFunction.class); - if (method != null && method.getModifier() != PyFunction.Modifier.STATICMETHOD) { - final PsiElement parent = namedParameter.getParent(); - if (parent instanceof PyParameterList && ((PyParameterList)parent).getParameters()[0] == namedParameter) { - continue; - } - } + // When function is inside a class, first parameter may be either self or cls which is always 'used'. + if (namedParameter.isSelf()) { + continue; } if (myIgnoreLambdaParameters && PsiTreeUtil.getParentOfType(element, Callable.class) instanceof PyLambdaExpression) { continue; diff --git a/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java index 5997138b0055..c855bd32c94a 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/AddMethodQuickFix.java @@ -69,7 +69,7 @@ public class AddMethodQuickFix implements LocalQuickFix { boolean made_instance = false; if (call_by_class) { if (args.length > 0) { - PyType first_arg_type = args[0].getType(TypeEvalContext.fast()); + PyType first_arg_type = TypeEvalContext.fast().getType(args[0]); if (first_arg_type instanceof PyClassType && ((PyClassType)first_arg_type).getPyClass().isSubclass(cls)) { // class, first arg ok: instance method builder.parameter("self"); // NOTE: might use a name other than 'self', according to code style. diff --git a/python/src/com/jetbrains/python/inspections/quickfix/ReformatFix.java b/python/src/com/jetbrains/python/inspections/quickfix/ReformatFix.java index 5f9879999f1a..560e4578256e 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/ReformatFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/ReformatFix.java @@ -1,5 +1,6 @@ package com.jetbrains.python.inspections.quickfix; +import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.intention.HighPriorityAction; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.LocalQuickFix; @@ -45,6 +46,9 @@ public class ReformatFix implements IntentionAction, LocalQuickFix, HighPriority @Override public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + if (!CodeInsightUtilBase.prepareFileForWrite(file)) { + return; + } CodeStyleManager.getInstance(project).reformat(file); } diff --git a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java index cc870bc2de18..bbee80818bea 100644 --- a/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java +++ b/python/src/com/jetbrains/python/packaging/PyPackageManagerImpl.java @@ -317,6 +317,7 @@ public class PyPackageManagerImpl extends PyPackageManager { } } finally { + clearCaches(); FileUtil.delete(new File(dirName)); //TODO: remove temp directory for remote interpreter } } diff --git a/python/src/com/jetbrains/python/packaging/setupPy/CreateSetupPyAction.java b/python/src/com/jetbrains/python/packaging/setupPy/CreateSetupPyAction.java index 2a969d67d5f7..9fcd9c49c149 100644 --- a/python/src/com/jetbrains/python/packaging/setupPy/CreateSetupPyAction.java +++ b/python/src/com/jetbrains/python/packaging/setupPy/CreateSetupPyAction.java @@ -1,6 +1,7 @@ package com.jetbrains.python.packaging.setupPy; import com.intellij.ide.IdeView; +import com.intellij.ide.fileTemplates.FileTemplate; import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.ide.fileTemplates.actions.AttributesDefaults; import com.intellij.ide.fileTemplates.actions.CreateFromTemplateAction; @@ -40,6 +41,12 @@ public class CreateSetupPyAction extends CreateFromTemplateAction { getTemplatePresentation().setText("Create setup.py"); } + @Override + public FileTemplate getTemplate() { + // to ensure changes are picked up, reload the template on every call (PY-6681) + return FileTemplateManager.getInstance().getInternalTemplate("Setup Script"); + } + @Override public void update(AnActionEvent e) { final Module module = e.getData(LangDataKeys.MODULE); diff --git a/python/src/com/jetbrains/python/parsing/StatementParsing.java b/python/src/com/jetbrains/python/parsing/StatementParsing.java index f07e7f8fbfab..37751366a56e 100644 --- a/python/src/com/jetbrains/python/parsing/StatementParsing.java +++ b/python/src/com/jetbrains/python/parsing/StatementParsing.java @@ -66,6 +66,11 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { } } + private void setExpectAsKeyword(boolean expectAsKeyword) { + myExpectAsKeyword = expectAsKeyword; + myBuilder.setTokenTypeRemapper(this); // clear cached token type + } + public void parseStatement(ParsingScope scope) { while (myBuilder.getTokenType() == PyTokenTypes.STATEMENT_BREAK) { @@ -472,14 +477,14 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { } } } - myExpectAsKeyword = true; // possible 'as' comes as an ident; reparse it as keyword if found + setExpectAsKeyword(true); // possible 'as' comes as an ident; reparse it as keyword if found if (builder.getTokenType() == PyTokenTypes.AS_KEYWORD) { builder.advanceLexer(); - myExpectAsKeyword = false; + setExpectAsKeyword(false); parseIdentifier(PyElementTypes.TARGET_EXPRESSION); } asMarker.done(elementType); - myExpectAsKeyword = false; + setExpectAsKeyword(false); if (builder.getTokenType() == PyTokenTypes.COMMA) { builder.advanceLexer(); if (in_parens && builder.getTokenType() == PyTokenTypes.RPAR) { @@ -527,14 +532,14 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { myBuilder.advanceLexer(); marker.done(getReferenceType()); boolean old_expect_AS_kwd = myExpectAsKeyword; - myExpectAsKeyword = expect_as; + setExpectAsKeyword(expect_as); while (myBuilder.getTokenType() == PyTokenTypes.DOT) { marker = marker.precede(); myBuilder.advanceLexer(); checkMatches(PyTokenTypes.IDENTIFIER, IDENTIFIER_EXPECTED); marker.done(getReferenceType()); } - myExpectAsKeyword = old_expect_AS_kwd; + setExpectAsKeyword(old_expect_AS_kwd); return true; } @@ -675,7 +680,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { if (!getExpressionParser().parseSingleExpression(false, false)) { myBuilder.error(EXPRESSION_EXPECTED); } - myExpectAsKeyword = true; + setExpectAsKeyword(true); if (myBuilder.getTokenType() == PyTokenTypes.COMMA || myBuilder.getTokenType() == PyTokenTypes.AS_KEYWORD) { myBuilder.advanceLexer(); if (!getExpressionParser().parseSingleExpression(true, false)) { @@ -730,7 +735,7 @@ public class StatementParsing extends Parsing implements ITokenTypeRemapper { while (true) { PsiBuilder.Marker withItem = myBuilder.mark(); getExpressionParser().parseExpression(); - myExpectAsKeyword = true; + setExpectAsKeyword(true); if (myBuilder.getTokenType() == PyTokenTypes.AS_KEYWORD) { myBuilder.advanceLexer(); getExpressionParser().parseSingleExpression(true, false); // 'as' is followed by a target diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index c31172bfe239..12a2870fe860 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -609,6 +609,12 @@ public class PyUtil { } } + public static String getElementNameWithoutExtension(PsiNamedElement psiNamedElement) { + return psiNamedElement instanceof PyFile + ? FileUtil.getNameWithoutExtension(((PyFile)psiNamedElement).getName()) + : psiNamedElement.getName(); + } + public static boolean hasUnresolvedAncestors(@NotNull PyClass cls) { for (PyClassRef classRef : cls.iterateAncestors()) { if (classRef.getPyClass() == null && classRef.getType() == null) { @@ -1065,7 +1071,7 @@ public class PyUtil { */ public static int getElementsCount(PyExpression expression, TypeEvalContext evalContext) { int valuesLength = -1; - PyType type = expression.getType(evalContext); + PyType type = evalContext.getType(expression); if (type instanceof PyTupleType) { valuesLength = ((PyTupleType)type).getElementCount(); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java index 1b5e21df8f3a..68cef9705ebf 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBinaryExpressionImpl.java @@ -108,7 +108,7 @@ public class PyBinaryExpressionImpl extends PyElementImpl implements PyBinaryExp return new PyOperatorReference(this, context); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyTypeChecker.AnalyzeCallResults results = PyTypeChecker.analyzeCall(this, context); if (results != null) { final PyType type = results.getCallable().getReturnType(context, this); diff --git a/python/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java index af6dd0090f52..497611ac73d3 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBoolLiteralExpressionImpl.java @@ -15,7 +15,7 @@ public class PyBoolLiteralExpressionImpl extends PyElementImpl implements PyBool super(astNode); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return PyBuiltinCache.getInstance(this).getBoolType(); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index aea70b28e570..f7b87c4ef41f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -360,12 +360,12 @@ public class PyCallExpressionHelper { final PyExpression[] args = call.getArguments(); if (args.length == 1) { final PyExpression arg = args[0]; - final PyType argType = arg.getType(context); + final PyType argType = context.getType(arg); if (argType instanceof PyClassType) { final PyClassType classType = (PyClassType)argType; if (!classType.isDefinition()) { final PyClass cls = classType.getPyClass(); - return cls.getType(context); + return context.getType(cls); } } else { diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java index b8d0fcb1cb0f..0fa29df39d2b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionImpl.java @@ -87,7 +87,7 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress return "PyCallExpression: " + PyUtil.getReadableRepr(getCallee(), true); //or: getCalledFunctionReference().getReferencedName(); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return PyCallExpressionHelper.getCallType(this, context); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 1c9e818fe85e..eabaa37e163a 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -55,7 +55,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement private volatile Map myPropertyCache; @Override - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return new PyClassTypeImpl(this, true); } @@ -276,7 +276,7 @@ public class PyClassImpl extends PyPresentableElementImpl implement result.add(new PyClassRef(element)); } else { - final PyType type = expression.getType(context); + final PyType type = context.getType(expression); if (type instanceof PyClassType) { result.add(new PyClassRef((PyClassType)type)); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyConditionalExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyConditionalExpressionImpl.java index 061b3c5117cb..4fb67b3b1fca 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyConditionalExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyConditionalExpressionImpl.java @@ -20,7 +20,7 @@ public class PyConditionalExpressionImpl extends PyElementImpl implements PyCond super(astNode); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyExpression truePart = getTruePart(); final PyExpression falsePart = getFalsePart(); if (truePart == null || falsePart == null) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java index b0c5d37004bd..05bee8401122 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyDecoratorImpl.java @@ -166,7 +166,7 @@ public class PyDecoratorImpl extends StubBasedPsiElementBase im } } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return PyCallExpressionHelper.getCallType(this, context); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyDictCompExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDictCompExpressionImpl.java index 37b010313f4f..48bdd9d46e0f 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyDictCompExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyDictCompExpressionImpl.java @@ -15,7 +15,7 @@ public class PyDictCompExpressionImpl extends PyComprehensionElementImpl impleme super(astNode); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return PyBuiltinCache.getInstance(this).getDictType(); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyDictLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyDictLiteralExpressionImpl.java index f5a507e6771f..7c66f1d195e6 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyDictLiteralExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyDictLiteralExpressionImpl.java @@ -22,7 +22,7 @@ public class PyDictLiteralExpressionImpl extends PyElementImpl implements PyDict return childrenToPsi(KEY_VALUE_EXPRESSIONS, PyKeyValueExpression.EMPTY_ARRAY); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return PyBuiltinCache.createLiteralCollectionType(this, "dict"); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyEmptyExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyEmptyExpressionImpl.java index da14e03f08d0..32fbdd6fd62d 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyEmptyExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyEmptyExpressionImpl.java @@ -14,7 +14,7 @@ public class PyEmptyExpressionImpl extends PyElementImpl implements PyEmptyExpre super(astNode); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return null; } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java index 4e23b2c6e93d..5408cd0b9aee 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFileImpl.java @@ -704,7 +704,7 @@ public class PyFileImpl extends PsiFileBase implements PyFile, PyExpression { } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { if (myType == null) myType = new PyModuleType(this); return myType; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyFromImportStatementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyFromImportStatementImpl.java index 4f98700bfccf..45877d1cfd57 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyFromImportStatementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyFromImportStatementImpl.java @@ -161,9 +161,13 @@ public class PyFromImportStatementImpl extends PyBaseElementImpl imp private static boolean isDynamicallyEvaluated(@NotNull Collection parameters, @NotNull TypeEvalContext context) { for (PyNamedParameter parameter : parameters) { - final PyType type = parameter.getType(context); + final PyType type = context.getType(parameter); if (type instanceof PyDynamicallyEvaluatedType) { return true; } @@ -245,7 +245,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp statements.accept(new PyRecursiveElementVisitor() { @Override public void visitPyYieldExpression(PyYieldExpression node) { - final PyType type = node.getType(context); + final PyType type = context.getType(node); if (node.isDelegating() && type instanceof PyCollectionType) { final PyCollectionType collectionType = (PyCollectionType)type; types.add(collectionType.getElementType(context)); @@ -330,7 +330,7 @@ public class PyFunctionImpl extends PyPresentableElementImpl imp } @Override - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyFunctionType type = new PyFunctionType(this); if (getDecoratorList() != null) { return PyUnionType.createWeakType(type); diff --git a/python/src/com/jetbrains/python/psi/impl/PyGeneratorExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyGeneratorExpressionImpl.java index 190a4eca6a13..8b8e91dc2db4 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyGeneratorExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyGeneratorExpressionImpl.java @@ -28,12 +28,12 @@ public class PyGeneratorExpressionImpl extends PyComprehensionElementImpl implem @Nullable @Override - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyExpression resultExpr = getResultExpression(); final PyBuiltinCache cache = PyBuiltinCache.getInstance(this); final PyClass generator = cache.getClass(PyNames.FAKE_GENERATOR); if (resultExpr != null && generator != null) { - final PyType elementType = resultExpr.getType(context); + final PyType elementType = context.getType(resultExpr); return new PyCollectionTypeImpl(generator, false, elementType); } return null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyKeyValueExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyKeyValueExpressionImpl.java index 22fe2800c770..40acfb1959cf 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyKeyValueExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyKeyValueExpressionImpl.java @@ -18,12 +18,12 @@ public class PyKeyValueExpressionImpl extends PyElementImpl implements PyKeyValu super(astNode); } - public PyType getType(@NotNull TypeEvalContext context) { - final PyType keyType = getKey().getType(context); + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { + final PyType keyType = context.getType(getKey()); final PyExpression value = getValue(); PyType valueType = null; if (value != null) { - valueType = value.getType(context); + valueType = context.getType(value); } return PyTupleType.create(this, new PyType[] {keyType, valueType}); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyKeywordArgumentImpl.java b/python/src/com/jetbrains/python/psi/impl/PyKeywordArgumentImpl.java index 02cba3fe8e95..d43636eba7f4 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyKeywordArgumentImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyKeywordArgumentImpl.java @@ -42,9 +42,9 @@ public class PyKeywordArgumentImpl extends PyElementImpl implements PyKeywordArg return getClass().getSimpleName() + ": " + getKeyword(); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyExpression e = getValueExpression(); - return e != null ? e.getType(context) : null; + return e != null ? context.getType(e) : null; } @Override diff --git a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java index 27380a9928fd..fc31ce2e21a3 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyLambdaExpressionImpl.java @@ -23,7 +23,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp pyVisitor.visitPyLambdaExpression(this); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return new PyFunctionType(this); } @@ -41,7 +41,7 @@ public class PyLambdaExpressionImpl extends PyElementImpl implements PyLambdaExp @Override public PyType getReturnType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { final PyExpression body = getBody(); - if (body != null) return body.getType(context); + if (body != null) return context.getType(body); else return null; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyListCompExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyListCompExpressionImpl.java index 8e34c714795d..86ccc3e8dda7 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyListCompExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyListCompExpressionImpl.java @@ -26,12 +26,12 @@ public class PyListCompExpressionImpl extends PyComprehensionElementImpl impleme @Nullable @Override - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyExpression resultExpr = getResultExpression(); final PyBuiltinCache cache = PyBuiltinCache.getInstance(this); final PyClass list = cache.getClass("list"); if (resultExpr != null && list != null) { - final PyType elementType = resultExpr.getType(context); + final PyType elementType = context.getType(resultExpr); return new PyCollectionTypeImpl(list, false, elementType); } return cache.getListType(); diff --git a/python/src/com/jetbrains/python/psi/impl/PyListLiteralExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyListLiteralExpressionImpl.java index c3b49b4938b1..3992aa4026ab 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyListLiteralExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyListLiteralExpressionImpl.java @@ -70,7 +70,7 @@ public class PyListLiteralExpressionImpl extends PyElementImpl implements PyList } } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { return PyBuiltinCache.createLiteralCollectionType(this, "list"); } } diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index 846b6fd27509..1ebeec40f793 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -9,6 +9,7 @@ import com.intellij.psi.stubs.IStubElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.intellij.util.PlatformIcons; +import com.jetbrains.cython.psi.CythonClass; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; @@ -153,15 +154,14 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl escapeMap = initializeEscapeMap(); private String stringValue; private List valueTextRanges; + private final DefaultRegExpPropertiesProvider myPropertiesProvider; private static Map initializeEscapeMap() { Map map = new HashMap(); @@ -51,6 +54,7 @@ public class PyStringLiteralExpressionImpl extends PyElementImpl implements PySt public PyStringLiteralExpressionImpl(ASTNode astNode) { super(astNode); + myPropertiesProvider = DefaultRegExpPropertiesProvider.getInstance(); } @Override @@ -291,7 +295,7 @@ public class PyStringLiteralExpressionImpl extends PyElementImpl implements PySt return true; } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final List nodes = getStringNodes(); if (nodes.size() > 0) { String text = getStringNodes().get(0).getText(); @@ -431,4 +435,27 @@ public class PyStringLiteralExpressionImpl extends PyElementImpl implements PySt public boolean supportsNamedGroupSyntax(RegExpGroup group) { return group.isPythonNamedGroup(); } + + @Override + public boolean isValidCategory(@NotNull String category) { + return myPropertiesProvider.isValidCategory(category); + } + + @NotNull + @Override + public String[][] getAllKnownProperties() { + return myPropertiesProvider.getAllKnownProperties(); + } + + @Nullable + @Override + public String getPropertyDescription(@Nullable String name) { + return myPropertiesProvider.getPropertyDescription(name); + } + + @NotNull + @Override + public String[][] getKnownCharacterClasses() { + return myPropertiesProvider.getKnownCharacterClasses(); + } } diff --git a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java index 60656f93d531..2a85a5e1a891 100644 --- a/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PySubscriptionExpressionImpl.java @@ -38,7 +38,7 @@ public class PySubscriptionExpressionImpl extends PyElementImpl implements PySub @Nullable @Override - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { PyType res = null; final PsiReference ref = getReference(PyResolveContext.noImplicits().withTypeEvalContext(context)); if (ref != null) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java index 9c3d3de54f1f..117983e93c69 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTargetExpressionImpl.java @@ -98,7 +98,7 @@ public class PyTargetExpressionImpl extends PyPresentableElementImpl results = type.resolveMember(name, null, AccessDirection.READ, PyResolveContext.noImplicits()); diff --git a/python/src/com/jetbrains/python/psi/impl/PyTupleExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTupleExpressionImpl.java index 98f9cea9df95..274a47584093 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTupleExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTupleExpressionImpl.java @@ -31,7 +31,7 @@ public class PyTupleExpressionImpl extends PyElementImpl implements PyTupleExpre return childrenToPsi(PythonDialectsTokenSetProvider.INSTANCE.getExpressionTokens(), PyExpression.EMPTY_ARRAY); } - public PyType getType(@NotNull TypeEvalContext context) { + public PyType getType(@NotNull TypeEvalContext context, @NotNull TypeEvalContext.Key key) { final PyExpression[] elements = getElements(); final PyType[] types = new PyType[elements.length]; for (int i = 0; i < types.length; i++) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java index 34daf762d8ff..69831de40578 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyTupleParameterImpl.java @@ -60,4 +60,9 @@ public class PyTupleParameterImpl extends PyPresentableElementImpl namesAlready = new HashSet(); ctx.put(PyType.CTX_NAMES, namesAlready); @@ -382,7 +382,7 @@ public class PyQualifiedReference extends PyReferenceImpl { final PyExpression qualifier = myElement.getQualifier(); if (qualifier != null) { final TypeEvalContext context = TypeEvalContext.fast(); - PyType qualifierType = qualifier.getType(context); + PyType qualifierType = context.getType(qualifier); if (qualifierType == null || qualifierType instanceof PyTypeReference) { return true; } diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index 30088c1af90a..af0f251a7ae8 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -144,26 +144,13 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference } @NotNull - private static ResolveResultList resolveToLatestDefs(@NotNull ScopeOwner owner, @NotNull PsiElement element, @NotNull String name) { + private static ResolveResultList resolveToLatestDefs(@NotNull List instructions, @NotNull PsiElement element, @NotNull String name) { final ResolveResultList ret = new ResolveResultList(); - final List instructions = PyDefUseUtil.getLatestDefs(owner, name, element, false); for (ReadWriteInstruction instruction : instructions) { PsiElement definition = instruction.getElement(); NameDefiner definer = null; // TODO: This check may slow down resolving, but it is the current solution to the comprehension scopes problem - final PyComprehensionElement definitionComprehension = PsiTreeUtil.getParentOfType(definition, PyComprehensionElement.class); - if (definitionComprehension != null) { - final boolean isAtLeast30 = LanguageLevel.forElement(definitionComprehension).isAtLeast(LanguageLevel.PYTHON30); - final boolean isListComprehension = definitionComprehension instanceof PyListCompExpression; - if (!isListComprehension || isAtLeast30) { - if (true) { - final PyComprehensionElement elementComprehension = PsiTreeUtil.getParentOfType(element, PyComprehensionElement.class); - if (elementComprehension == null || !PsiTreeUtil.isAncestor(definitionComprehension, elementComprehension, false)) { - continue; - } - } - } - } + if (isInnerComprehension(element, definition)) continue; if (definition instanceof NameDefiner && !(definition instanceof PsiNamedElement)) { definer = (NameDefiner)definition; definition = definer.getElementNamed(name); @@ -201,6 +188,29 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference return results; } + private static boolean isInnerComprehension(PsiElement referenceElement, PsiElement definition) { + final PyComprehensionElement definitionComprehension = PsiTreeUtil.getParentOfType(definition, PyComprehensionElement.class); + if (definitionComprehension != null && isOwnScopeComprehension(definitionComprehension)) { + final PyComprehensionElement elementComprehension = PsiTreeUtil.getParentOfType(referenceElement, PyComprehensionElement.class); + if (elementComprehension == null || !PsiTreeUtil.isAncestor(definitionComprehension, elementComprehension, false)) { + return true; + } + } + return false; + } + + private static boolean isOwnScopeComprehension(PsiElement definitionComprehension) { + final boolean isAtLeast30 = LanguageLevel.forElement(definitionComprehension).isAtLeast(LanguageLevel.PYTHON30); + final boolean isListComprehension = definitionComprehension instanceof PyListCompExpression; + return !isListComprehension || isAtLeast30; + } + + private static boolean isInOwnScopeComprehension(PsiElement uexpr) { + PyComprehensionElement comprehensionElement = PsiTreeUtil.getParentOfType(uexpr, PyComprehensionElement.class); + return comprehensionElement != null && isOwnScopeComprehension(comprehensionElement); + } + + /** * Does actual resolution of resolve(). * @@ -248,15 +258,16 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference uexpr = null; } else if (owner == originalOwner && !scope.isGlobal(referencedName)) { - final ResolveResultList latest = resolveToLatestDefs(owner, myElement, referencedName); + final List instructions = PyDefUseUtil.getLatestDefs(owner, referencedName, myElement, false); + final ResolveResultList latest = resolveToLatestDefs(instructions, myElement, referencedName); if (!latest.isEmpty()) { return latest; } - if (owner instanceof PyClass) { - final ScopeOwner classOwner = ScopeUtil.getScopeOwner(owner); - if (classOwner != null) { + if (owner instanceof PyClass || (instructions.isEmpty() && isInOwnScopeComprehension(uexpr))) { + final ScopeOwner parentOwner = ScopeUtil.getScopeOwner(owner); + if (parentOwner != null) { processor = new ResolveProcessor(referencedName); - PyResolveUtil.scopeCrawlUp(processor, classOwner, referencedName, roof); + PyResolveUtil.scopeCrawlUp(processor, parentOwner, referencedName, roof); uexpr = processor.getResult(); } } @@ -288,8 +299,9 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference if (uexpr == null) { // ...as a part of current module PyType otype = builtins_cache.getObjectType(); // "object" as a closest kin to "module" - if (otype != null) { - ret.addAll(otype.resolveMember(myElement.getName(), null, AccessDirection.READ, myContext)); + String name = myElement.getName(); + if (otype != null && name != null) { + ret.addAll(otype.resolveMember(name, null, AccessDirection.READ, myContext)); } } if (uexpr == null) { @@ -446,6 +458,12 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference return true; } + // we shadow their name or they shadow ours (PY-6241) + if (resolveResult instanceof PsiNamedElement && resolveResult instanceof ScopeOwner && element instanceof ScopeOwner && + theirScopeOwner == ScopeUtil.getScopeOwner(resolveResult)) { + return true; + } + if (!haveQualifiers(element) && ourScopeOwner != null && theirScopeOwner != null) { if (resolvesToSameGlobal(element, elementName, ourScopeOwner, theirScopeOwner, resolveResult)) return true; } diff --git a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java index 4b786de3e974..51839aa1f6bf 100644 --- a/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java +++ b/python/src/com/jetbrains/python/psi/resolve/QualifiedNameResolverImpl.java @@ -201,6 +201,9 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso addResultsFromRoots(); } + mySourceResults.addAll(myLibResults); + myLibResults.clear(); + if (!myWithoutForeign) { for (PyImportResolver resolver : Extensions.getExtensions(PyImportResolver.EP_NAME)) { PsiElement foreign = resolver.resolveImportReference(myQualifiedName, myContext); @@ -210,9 +213,6 @@ public class QualifiedNameResolverImpl implements RootVisitor, QualifiedNameReso } } - mySourceResults.addAll(myLibResults); - myLibResults.clear(); - return Lists.newArrayList(mySourceResults); } diff --git a/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java b/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java index 96e067dff963..f79cb9014052 100644 --- a/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java +++ b/python/src/com/jetbrains/python/psi/resolve/VariantsProcessor.java @@ -50,9 +50,7 @@ public abstract class VariantsProcessor implements PsiScopeProcessor { // TODO: refactor to look saner; much code duplication if (element instanceof PsiNamedElement) { final PsiNamedElement psiNamedElement = (PsiNamedElement)element; - final String name = psiNamedElement instanceof PyFile - ? FileUtil.getNameWithoutExtension(((PyFile)psiNamedElement).getName()) - : psiNamedElement.getName(); + final String name = PyUtil.getElementNameWithoutExtension(psiNamedElement); if (name != null && nameIsAcceptable(name)) { addElement(name, psiNamedElement); } diff --git a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java index 7dfd2861482f..0fb2f10830eb 100644 --- a/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyClassTypeImpl.java @@ -91,7 +91,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { } @Nullable - public List resolveMember(final String name, @Nullable PyExpression location, AccessDirection direction, + public List resolveMember(@NotNull final String name, @Nullable PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { final Set> resolving = ourResolveMemberStack.get(); final Pair key = Pair.create(myClass, name); @@ -136,7 +136,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { // methods of super() call are not of class super! PyExpression first_arg = ((PyCallExpression)location).getArgument(0, PyExpression.class); if (first_arg != null) { // the usual case: first arg is the derived class that super() is proxying for - PyType first_arg_type = first_arg.getType(resolveContext.getTypeEvalContext()); + PyType first_arg_type = resolveContext.getTypeEvalContext().getType(first_arg); if (first_arg_type instanceof PyClassType) { PyClass derived_class = ((PyClassType)first_arg_type).getPyClass(); final Iterator base_it = derived_class.iterateAncestorClasses().iterator(); @@ -212,7 +212,7 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { private PyClassType getMetaclassType() { final PyTargetExpression metaClassAttribute = myClass.findClassAttribute(PyNames.DUNDER_METACLASS, true); if (metaClassAttribute != null) { - final PyType type = metaClassAttribute.getType(TypeEvalContext.fastStubOnly(null)); + final PyType type = TypeEvalContext.fastStubOnly(null).getType(metaClassAttribute); if (type instanceof PyClassType) { return (PyClassType)type; } @@ -381,7 +381,8 @@ public class PyClassTypeImpl extends UserDataHolderBase implements PyClassType { type = new PyClassTypeImpl((PyClass)element, myIsDefinition); } else { - type = expression.getType(TypeEvalContext.fastStubOnly(myClass.getContainingFile())); + final TypeEvalContext typeEvalContext = TypeEvalContext.fastStubOnly(myClass.getContainingFile()); + type = typeEvalContext.getType(expression); if (type instanceof PyClassType && !myIsDefinition) { type = ((PyClassType)type).toInstance(); } diff --git a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java index e66c3a7069bf..8b68d03094a8 100644 --- a/python/src/com/jetbrains/python/psi/types/PyFunctionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyFunctionType.java @@ -29,7 +29,7 @@ public class PyFunctionType implements PyCallableType { } @Override - public List resolveMember(String name, + public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { diff --git a/python/src/com/jetbrains/python/psi/types/PyGenericType.java b/python/src/com/jetbrains/python/psi/types/PyGenericType.java index 27655d3c330c..9c0b0245c764 100644 --- a/python/src/com/jetbrains/python/psi/types/PyGenericType.java +++ b/python/src/com/jetbrains/python/psi/types/PyGenericType.java @@ -22,7 +22,7 @@ public class PyGenericType implements PyType { @Nullable @Override - public List resolveMember(String name, + public List resolveMember(@NotNull String name, @Nullable PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { diff --git a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java index 9a06a4f61263..fd4b93f5f7fe 100644 --- a/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyImportedModuleType.java @@ -5,6 +5,8 @@ import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.util.ProcessingContext; +import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; +import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyFile; @@ -33,7 +35,7 @@ public class PyImportedModuleType implements PyType { @Nullable @Override - public List resolveMember(String name, + public List resolveMember(@NotNull String name, PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { @@ -51,7 +53,9 @@ public class PyImportedModuleType implements PyType { public Object[] getCompletionVariants(String completionPrefix, PyExpression location, ProcessingContext context) { List result = new ArrayList(); - final List importTargets = myImportedModule.getContainingFile().getImportTargets(); + ScopeOwner scopeOwner = ScopeUtil.getScopeOwner(location); + assert scopeOwner != null; + final List importTargets = PyModuleType.getVisibleImports(scopeOwner); final int imported = myImportedModule.getImportedPrefix().getComponentCount(); for (PyImportElement importTarget : importTargets) { final PyQualifiedName qName = importTarget.getImportedQName(); diff --git a/python/src/com/jetbrains/python/psi/types/PyLiteralCollectionType.java b/python/src/com/jetbrains/python/psi/types/PyLiteralCollectionType.java index cab7a96a6fd7..159deb29958d 100644 --- a/python/src/com/jetbrains/python/psi/types/PyLiteralCollectionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyLiteralCollectionType.java @@ -27,7 +27,7 @@ public class PyLiteralCollectionType extends PyClassTypeImpl implements PyCollec return null; } for (int i = 1; i < elements.length; i++) { - PyType elementType = elements [i].getType(context); + PyType elementType = context.getType(elements[i]); if (elementType == null || !elementType.equals(result)) { return null; } diff --git a/python/src/com/jetbrains/python/psi/types/PyModuleType.java b/python/src/com/jetbrains/python/psi/types/PyModuleType.java index e4e1754fdce5..6213aef01a37 100644 --- a/python/src/com/jetbrains/python/psi/types/PyModuleType.java +++ b/python/src/com/jetbrains/python/psi/types/PyModuleType.java @@ -58,7 +58,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje @Nullable @Override - public List resolveMember(final String name, + public List resolveMember(@NotNull final String name, @Nullable PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { @@ -167,7 +167,7 @@ public class PyModuleType implements PyType { // Modules don't descend from obje } @NotNull - private static List getVisibleImports(@NotNull ScopeOwner owner) { + public static List getVisibleImports(@NotNull ScopeOwner owner) { final List visibleImports = new ArrayList(); PyResolveUtil.scopeCrawlUp(new PsiScopeProcessor() { @Override diff --git a/python/src/com/jetbrains/python/psi/types/PyNoneType.java b/python/src/com/jetbrains/python/psi/types/PyNoneType.java index 3cacd7a081b8..e34ba6f94c6c 100644 --- a/python/src/com/jetbrains/python/psi/types/PyNoneType.java +++ b/python/src/com/jetbrains/python/psi/types/PyNoneType.java @@ -6,6 +6,7 @@ import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.List; @@ -20,7 +21,7 @@ public class PyNoneType implements PyType { // TODO must extend ClassType. It's } @Nullable - public List resolveMember(final String name, + public List resolveMember(@NotNull final String name, PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java index 8c3caf7f37b1..80ff2bb3b929 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeChecker.java @@ -48,8 +48,11 @@ public class PyTypeChecker { if (expected == null || actual == null) { return true; } - if (isObjectType(expected) || isObjectType(actual)) { - return true; + if (expected instanceof PyClassType) { + final PyClass c = ((PyClassType)expected).getPyClass(); + if (c != null && "object".equals(c.getName())) { + return true; + } } if ((expected instanceof PyTypeReference || actual instanceof PyTypeReference) && !recursive) { return true; @@ -158,16 +161,6 @@ public class PyTypeChecker { return false; } - private static boolean isObjectType(@NotNull PyType type) { - if (type instanceof PyClassType) { - final PyClass c = ((PyClassType)type).getPyClass(); - if ("object".equals(c.getName())) { - return true; - } - } - return false; - } - public static boolean isUnknown(@Nullable PyType type) { if (type == null || type instanceof PyTypeReference || type instanceof PyGenericType) { return true; @@ -261,8 +254,8 @@ public class PyTypeChecker { final Map substitutions = collectCallGenerics(function, receiver, context); for (Map.Entry entry : arguments.entrySet()) { final PyNamedParameter p = entry.getValue(); - final PyType argType = entry.getKey().getType(context); - final PyType paramType = p.getType(context); + final PyType argType = context.getType(entry.getKey()); + final PyType paramType = context.getType(p); if (!match(paramType, argType, context, substitutions)) { return null; } @@ -276,7 +269,7 @@ public class PyTypeChecker { final Map substitutions = new LinkedHashMap(); // Collect generic params of object type final Set generics = new LinkedHashSet(); - final PyType qualifierType = receiver != null ? receiver.getType(context) : null; + final PyType qualifierType = receiver != null ? context.getType(receiver) : null; collectGenerics(qualifierType, context, generics, new HashSet()); for (PyGenericType t : generics) { substitutions.put(t, t); @@ -352,7 +345,7 @@ public class PyTypeChecker { final PsiElement resolved = result.getElement(); if (resolved instanceof PyTypedElement) { final PyTypedElement typedElement = (PyTypedElement)resolved; - final PyType type = typedElement.getType(context); + final PyType type = context.getType(typedElement); if (!(type instanceof PyFunctionType)) { return null; } @@ -370,7 +363,7 @@ public class PyTypeChecker { if (firstResults == null) { firstResults = results; } - if (match(param.getType(context), arg.getType(context), context)) { + if (match(context.getType(param), context.getType(arg), context)) { return results; } } @@ -388,7 +381,7 @@ public class PyTypeChecker { final PsiReference ref = expr.getReference(PyResolveContext.noImplicits().withTypeEvalContext(context)); final PsiElement resolved = ref.resolve(); if (resolved instanceof PyTypedElement) { - final PyType type = ((PyTypedElement)resolved).getType(context); + final PyType type = context.getType((PyTypedElement)resolved); if (type instanceof PyFunctionType) { final Callable callable = ((PyFunctionType)type).getCallable(); final PyParameter[] parameters = callable.getParameterList().getParameters(); @@ -479,10 +472,13 @@ public class PyTypeChecker { public static boolean isResolvedToSeveralMethods(@NotNull PyQualifiedExpression callee, @NotNull TypeEvalContext context) { final PyExpression qualifier = callee.getQualifier(); if (qualifier != null) { - final PyType qualifierType = qualifier.getType(context); + final PyType qualifierType = context.getType(qualifier); if (qualifierType instanceof PyUnionType) { final PyUnionType unionType = (PyUnionType)qualifierType; final String name = callee.getName(); + if (name == null) { + return false; + } int sameNameCount = 0; for (PyType member : unionType.getMembers()) { if (member != null) { diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java index f2ec421d91ee..f7e20b6c94d2 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeParser.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeParser.java @@ -246,7 +246,7 @@ public class PyTypeParser { final RatedResolveResult result = results.get(0); final PsiElement resolved = result.getElement(); if (resolved instanceof PyTypedElement) { - PyType t = ((PyTypedElement)resolved).getType(context.getTypeEvalContext()); + PyType t = context.getTypeEvalContext().getType((PyTypedElement)resolved); if (t instanceof PyClassType) { t = ((PyClassType)t).toInstance(); } diff --git a/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java b/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java index 1d659bdc4a8a..1727ed264e64 100644 --- a/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/types/PyTypeReferenceImpl.java @@ -20,7 +20,7 @@ import java.util.Set; */ public abstract class PyTypeReferenceImpl implements PyTypeReference { @NotNull - public List resolveMember(String name, + public List resolveMember(@NotNull String name, PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { diff --git a/python/src/com/jetbrains/python/psi/types/PyUnionType.java b/python/src/com/jetbrains/python/psi/types/PyUnionType.java index f22042dbc126..0e1e62873eb0 100644 --- a/python/src/com/jetbrains/python/psi/types/PyUnionType.java +++ b/python/src/com/jetbrains/python/psi/types/PyUnionType.java @@ -8,6 +8,7 @@ import com.jetbrains.python.psi.AccessDirection; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.resolve.RatedResolveResult; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -23,7 +24,7 @@ public class PyUnionType implements PyType { } @Nullable - public List resolveMember(String name, + public List resolveMember(@NotNull String name, PyExpression location, AccessDirection direction, PyResolveContext resolveContext) { diff --git a/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java b/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java index fa06d2093ea9..abd91f32fc58 100644 --- a/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java +++ b/python/src/com/jetbrains/python/refactoring/PyReplaceExpressionUtil.java @@ -111,7 +111,7 @@ public class PyReplaceExpressionUtil implements PyElementTypes { } else { final TypeEvalContext context = TypeEvalContext.slow(); - final PyType valueType = formatValue.getType(context); + final PyType valueType = context.getType(formatValue); final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(oldExpression); final PyType tupleType = builtinCache.getTupleType(); final PyType mappingType = PyTypeParser.getTypeByName(null, "collections.Mapping"); diff --git a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java index 8f970440f578..6f6bed984a18 100644 --- a/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java +++ b/python/src/com/jetbrains/python/refactoring/introduce/IntroduceHandler.java @@ -189,7 +189,7 @@ abstract public class IntroduceHandler implements RefactoringActionHandler { candidates.addAll(NameSuggesterUtil.generateNames(text)); } final TypeEvalContext context = TypeEvalContext.slow(); - PyType type = expression.getType(context); + PyType type = context.getType(expression); if (type != null && type != PyNoneType.INSTANCE) { String typeName = type.getName(); if (typeName != null) { diff --git a/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalData.java b/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalData.java index eee2a9d72edb..713c56f319d0 100644 --- a/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalData.java +++ b/python/src/com/jetbrains/python/remote/PyRemoteSdkAdditionalData.java @@ -286,9 +286,12 @@ public final class PyRemoteSdkAdditionalData extends PythonSdkAdditionalData imp @Nullable @Override - public Object clone() throws CloneNotSupportedException { + public PyRemoteSdkAdditionalData clone() { try { final PyRemoteSdkAdditionalData copy = (PyRemoteSdkAdditionalData)super.clone(); + if (copy == null) { + return null; + } copyTo(copy); return copy; diff --git a/python/src/com/jetbrains/python/sdk/PySdkUtil.java b/python/src/com/jetbrains/python/sdk/PySdkUtil.java index e046208c72c6..0932a371f69d 100644 --- a/python/src/com/jetbrains/python/sdk/PySdkUtil.java +++ b/python/src/com/jetbrains/python/sdk/PySdkUtil.java @@ -182,27 +182,6 @@ public class PySdkUtil { } } - /** - * Finds the first match in a list os Strings. - * - * @param lines list of lines, may be null. - * @param regex pattern to match to. - * @return pattern's first matched group, or entire matched string if pattern has no groups, or null. - */ - @Nullable - public static String getFirstMatch(List lines, Pattern regex) { - if (lines == null) return null; - for (String s : lines) { - Matcher m = regex.matcher(s); - if (m.matches()) { - if (m.groupCount() > 0) { - return m.group(1); - } - } - } - return null; - } - public static boolean isRemote(@Nullable Sdk sdk) { return sdk != null && sdk.getSdkAdditionalData() instanceof RemoteCredentials; } diff --git a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java index 000f67ba2d8c..09debcfe2889 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/PythonSdkFlavor.java @@ -10,6 +10,7 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.encoding.EncodingManager; +import com.intellij.util.PatternUtil; import com.jetbrains.python.psi.LanguageLevel; import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonEnvUtil; @@ -173,11 +174,11 @@ public abstract class PythonSdkFlavor { return null; } Pattern pattern = Pattern.compile(version_regexp); - final String result = PySdkUtil.getFirstMatch(process_output.getStderrLines(), pattern); + final String result = PatternUtil.getFirstMatch(process_output.getStderrLines(), pattern); if (result != null) { return result; } - return PySdkUtil.getFirstMatch(process_output.getStdoutLines(), pattern); + return PatternUtil.getFirstMatch(process_output.getStdoutLines(), pattern); } public Collection getExtraDebugOptions() { diff --git a/python/src/com/jetbrains/python/statistics/PyInterpreterUsagesCollector.java b/python/src/com/jetbrains/python/statistics/PyInterpreterUsagesCollector.java index b66718b7b264..a1c5830a932b 100644 --- a/python/src/com/jetbrains/python/statistics/PyInterpreterUsagesCollector.java +++ b/python/src/com/jetbrains/python/statistics/PyInterpreterUsagesCollector.java @@ -27,7 +27,10 @@ public class PyInterpreterUsagesCollector extends AbstractApplicationUsagesColle for(Module m: ModuleManager.getInstance(project).getModules()) { Sdk pythonSdk = PythonSdkType.findPythonSdk(m); if (pythonSdk != null) { - result.add(new UsageDescriptor(pythonSdk.getVersionString(), 1)); + String versionString = pythonSdk.getVersionString(); + if (versionString != null) { + result.add(new UsageDescriptor(versionString, 1)); + } } } return result; diff --git a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java index e388a44b8333..b2e70a75b6a7 100644 --- a/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java +++ b/python/src/com/jetbrains/python/statistics/PyPackageUsagesCollector.java @@ -4,6 +4,7 @@ import com.intellij.internal.statistic.AbstractApplicationUsagesCollector; import com.intellij.internal.statistic.CollectUsagesException; import com.intellij.internal.statistic.beans.GroupDescriptor; import com.intellij.internal.statistic.beans.UsageDescriptor; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; @@ -26,26 +27,31 @@ public class PyPackageUsagesCollector extends AbstractApplicationUsagesCollector @NotNull @Override public Set getProjectUsages(@NotNull Project project) throws CollectUsagesException { - Set result = new HashSet(); - for(Module m: ModuleManager.getInstance(project).getModules()) { + final Set result = new HashSet(); + for(final Module m: ModuleManager.getInstance(project).getModules()) { Sdk pythonSdk = PythonSdkType.findPythonSdk(m); if (pythonSdk != null) { - List requirements = PyPackageManagerImpl.getRequirements(m); - if (requirements != null) { - Collection packages; - try { - packages = new HashSet(PyPIPackageUtil.INSTANCE.getPackageNames()); - } - catch (IOException e) { - continue; - } - for (PyRequirement requirement : requirements) { - String name = requirement.getName(); - if (packages.contains(name)) { - result.add(new UsageDescriptor(name, 1)); + ApplicationManager.getApplication().runReadAction(new Runnable() { + @Override + public void run() { + List requirements = PyPackageManagerImpl.getRequirements(m); + if (requirements != null) { + Collection packages; + try { + packages = new HashSet(PyPIPackageUtil.INSTANCE.getPackageNames()); + } + catch (IOException e) { + return; + } + for (PyRequirement requirement : requirements) { + String name = requirement.getName(); + if (packages.contains(name)) { + result.add(new UsageDescriptor(name, 1)); + } + } } } - } + }); } } return result; diff --git a/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java b/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java index 3e665a2e6be8..ce7bc9e85ebd 100644 --- a/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java +++ b/python/src/com/jetbrains/python/validation/HighlightingAnnotator.java @@ -3,9 +3,6 @@ package com.jetbrains.python.validation; import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.Annotation; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.ArrayUtil; -import com.jetbrains.cython.psi.CythonClass; -import com.jetbrains.python.PyNames; import com.jetbrains.python.highlighting.PyHighlighter; import com.jetbrains.python.psi.*; @@ -18,7 +15,7 @@ public class HighlightingAnnotator extends PyAnnotator { PyFunction function = PsiTreeUtil.getParentOfType(node, PyFunction.class); if (function != null) { Annotation annotation = getHolder().createInfoAnnotation(node, null); - annotation.setTextAttributes(isSelf(node, function) ? PyHighlighter.PY_SELF_PARAMETER : PyHighlighter.PY_PARAMETER); + annotation.setTextAttributes(node.isSelf() ? PyHighlighter.PY_SELF_PARAMETER : PyHighlighter.PY_PARAMETER); } } @@ -31,7 +28,7 @@ public class HighlightingAnnotator extends PyAnnotator { final PyNamedParameter element = function.getParameterList().findParameterByName(referencedName); if (element != null) { Annotation annotation = getHolder().createInfoAnnotation(node, null); - annotation.setTextAttributes(isSelf(element, function) ? PyHighlighter.PY_SELF_PARAMETER : PyHighlighter.PY_PARAMETER); + annotation.setTextAttributes(element.isSelf() ? PyHighlighter.PY_SELF_PARAMETER : PyHighlighter.PY_PARAMETER); } } } @@ -45,28 +42,4 @@ public class HighlightingAnnotator extends PyAnnotator { annotation.setTextAttributes(PyHighlighter.PY_KEYWORD_ARGUMENT); } } - - private static boolean isSelf(PyParameter node, PyFunction function) { - final PyNamedParameter named = node.getAsNamed(); - if (named != null) { - if (named.isPositionalContainer() || named.isKeywordContainer()) { - return false; - } - } - final int index = ArrayUtil.find(function.getParameterList().getParameters(), node); - final PyClass cls = function.getContainingClass(); - if (cls != null && index == 0) { - if (cls instanceof CythonClass && ((CythonClass)cls).isCppClass()) { - return false; - } - if (PyNames.NEW.equals(function.getName())) { - return true; - } - final PyFunction.Modifier modifier = function.getModifier(); - if (modifier != PyFunction.Modifier.CLASSMETHOD && modifier != PyFunction.Modifier.STATICMETHOD) { - return true; - } - } - return false; - } } diff --git a/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java b/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java index ec07ef4f134c..98fd2eb652e3 100644 --- a/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java +++ b/python/src/com/jetbrains/python/validation/Pep8ExternalAnnotator.java @@ -11,6 +11,9 @@ import com.intellij.execution.process.ProcessOutput; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.ExternalAnnotator; +import com.intellij.openapi.application.ApplicationInfo; +import com.intellij.openapi.application.impl.ApplicationInfoImpl; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorSettingsExternalizable; import com.intellij.openapi.module.ModuleUtilCore; @@ -47,6 +50,7 @@ import java.util.regex.Pattern; * @author yole */ public class Pep8ExternalAnnotator extends ExternalAnnotator { + private static final Logger LOG = Logger.getInstance(Pep8ExternalAnnotator.class); public static class Problem { private final int myLine; @@ -128,6 +132,9 @@ public class Pep8ExternalAnnotator extends ExternalAnnotator diff --git a/python/testData/completion/py3668/foo/__init__.py b/python/testData/completion/py3668/foo/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/py3668/foo/bar.py b/python/testData/completion/py3668/foo/bar.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/completion/py3668/py3668.after.py b/python/testData/completion/py3668/py3668.after.py new file mode 100644 index 000000000000..352310d2ca45 --- /dev/null +++ b/python/testData/completion/py3668/py3668.after.py @@ -0,0 +1,3 @@ +def func(): + import foo.bar + foo.bar diff --git a/python/testData/completion/py3668/py3668.py b/python/testData/completion/py3668/py3668.py new file mode 100644 index 000000000000..f3f5379fc8c9 --- /dev/null +++ b/python/testData/completion/py3668/py3668.py @@ -0,0 +1,3 @@ +def func(): + import foo.bar + foo. diff --git a/python/testData/findUsages/NameShadowing.py b/python/testData/findUsages/NameShadowing.py new file mode 100644 index 000000000000..fa06cb85b844 --- /dev/null +++ b/python/testData/findUsages/NameShadowing.py @@ -0,0 +1,16 @@ +class C(object): + def __init__(self): + self._x = None + + @property + def x(self): + """I'm the 'x' property.""" + return self._x + + @x.setter + def x(self, value): + self._x = value + + @x.deleter + def x(self): + del self._x \ No newline at end of file diff --git a/python/testData/formatter/longWith.py b/python/testData/formatter/longWith.py new file mode 100644 index 000000000000..a34fd4294994 --- /dev/null +++ b/python/testData/formatter/longWith.py @@ -0,0 +1,3 @@ +with really_long_name_of_the_function_with_a_lot_of_params( + param1, param2, param3) as item: + pass \ No newline at end of file diff --git a/python/testData/formatter/longWith_after.py b/python/testData/formatter/longWith_after.py new file mode 100644 index 000000000000..c6aacb7cde67 --- /dev/null +++ b/python/testData/formatter/longWith_after.py @@ -0,0 +1,3 @@ +with really_long_name_of_the_function_with_a_lot_of_params( + param1, param2, param3) as item: + pass \ No newline at end of file diff --git a/python/testData/intentions/afterTypeInDocstring.py b/python/testData/intentions/afterTypeInDocstring.py index 910a0afdb11f..fa2dab51d1b3 100644 --- a/python/testData/intentions/afterTypeInDocstring.py +++ b/python/testData/intentions/afterTypeInDocstring.py @@ -1,5 +1,6 @@ def foo(a, b): """ + :type a: object """ a. diff --git a/python/testData/intentions/afterTypeInDocstring1.py b/python/testData/intentions/afterTypeInDocstring1.py index 3422432d15c7..1eb6510bc70f 100644 --- a/python/testData/intentions/afterTypeInDocstring1.py +++ b/python/testData/intentions/afterTypeInDocstring1.py @@ -1,5 +1,6 @@ def foo(a, b): """ + :rtype : object """ b = 1 \ No newline at end of file diff --git a/python/testData/intentions/afterTypeInDocstring2.py b/python/testData/intentions/afterTypeInDocstring2.py index d38dfb10211b..cc1fe71acf10 100644 --- a/python/testData/intentions/afterTypeInDocstring2.py +++ b/python/testData/intentions/afterTypeInDocstring2.py @@ -1,5 +1,6 @@ def func1(x): """ + :rtype : object """ return x diff --git a/python/testData/intentions/afterTypeInDocstring3.py b/python/testData/intentions/afterTypeInDocstring3.py index 009561da2dca..508df1bf9e0f 100644 --- a/python/testData/intentions/afterTypeInDocstring3.py +++ b/python/testData/intentions/afterTypeInDocstring3.py @@ -1,5 +1,6 @@ def foo3(x, y, z, aa): #comment """ + :type y: object """ i = xx + y + z diff --git a/python/testData/intentions/afterTypeInDocstring4.py b/python/testData/intentions/afterTypeInDocstring4.py index 56fc78a28593..833eb614bfe5 100644 --- a/python/testData/intentions/afterTypeInDocstring4.py +++ b/python/testData/intentions/afterTypeInDocstring4.py @@ -2,5 +2,6 @@ class ProjectElement(object): def __init__(self, project_name='', info_source='', project_id=None, has_revisions=True): """ + :type project_name: object """ \ No newline at end of file diff --git a/python/testData/intentions/afterTypeInDocstring5.py b/python/testData/intentions/afterTypeInDocstring5.py index 8ef60a61ec1a..d8bb2c5e2f1c 100644 --- a/python/testData/intentions/afterTypeInDocstring5.py +++ b/python/testData/intentions/afterTypeInDocstring5.py @@ -1,5 +1,6 @@ def foo3(param): """ + :type param: object """ i = param.unresolved() \ No newline at end of file diff --git a/python/testData/resolve/GeneratorShadowing.py b/python/testData/resolve/GeneratorShadowing.py new file mode 100644 index 000000000000..eea177c5542f --- /dev/null +++ b/python/testData/resolve/GeneratorShadowing.py @@ -0,0 +1,9 @@ +def _(arg): + print(arg) + +def foo(): + _("foo") # This call is underlined by the inspector as an unresolved reference +# + print("\n".join("bar" for _ in range(5))) + +foo() diff --git a/python/testSrc/com/jetbrains/python/PyAddImportTest.java b/python/testSrc/com/jetbrains/python/PyAddImportTest.java index e8bc09255db0..a3c5fbff703e 100644 --- a/python/testSrc/com/jetbrains/python/PyAddImportTest.java +++ b/python/testSrc/com/jetbrains/python/PyAddImportTest.java @@ -20,14 +20,22 @@ public class PyAddImportTest extends PyTestCase { myFixture.checkResultByFile("addImport/addBuiltin.after.py"); } - public void testImportInParens() { // PY-7400 - myFixture.configureByFile("addImport/parens.py"); + public void testParens() { // PY-7400 + doAddImportFrom("urllib", "unquote_plus"); + } + + public void testComment() { // PY-8034 + doAddImportFrom("urllib", "unquote_plus"); + } + + private void doAddImportFrom(final String path, final String name) { + myFixture.configureByFile("addImport/" + getTestName(true) + ".py"); new WriteCommandAction(myFixture.getProject(), myFixture.getFile()) { @Override protected void run(Result result) throws Throwable { - AddImportHelper.addImportFrom(myFixture.getFile(), null, "urllib", "unquote_plus", null, AddImportHelper.ImportPriority.BUILTIN); + AddImportHelper.addImportFrom(myFixture.getFile(), null, path, name, null, AddImportHelper.ImportPriority.BUILTIN); } }.execute(); - myFixture.checkResultByFile("addImport/parens.after.py"); + myFixture.checkResultByFile("addImport/" + getTestName(true) + ".after.py"); } } diff --git a/python/testSrc/com/jetbrains/python/PyClassNameCompletionTest.java b/python/testSrc/com/jetbrains/python/PyClassNameCompletionTest.java index 11d8d770e356..c4fea2e2093a 100644 --- a/python/testSrc/com/jetbrains/python/PyClassNameCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PyClassNameCompletionTest.java @@ -18,15 +18,7 @@ public class PyClassNameCompletionTest extends PyTestCase { } public void testQualified() { - final PyCodeInsightSettings settings = PyCodeInsightSettings.getInstance(); - boolean oldValue = settings.PREFER_FROM_IMPORT; - settings.PREFER_FROM_IMPORT = false; - try { - doTest(); - } - finally { - settings.PREFER_FROM_IMPORT = oldValue; - } + doTestWithoutFromImport(); } public void testFunction() { @@ -45,6 +37,22 @@ public class PyClassNameCompletionTest extends PyTestCase { doTest(); } + public void testSubmoduleRegularImport() { // PY-7887 + doTestWithoutFromImport(); + } + + private void doTestWithoutFromImport() { + final PyCodeInsightSettings settings = PyCodeInsightSettings.getInstance(); + boolean oldValue = settings.PREFER_FROM_IMPORT; + settings.PREFER_FROM_IMPORT = false; + try { + doTest(); + } + finally { + settings.PREFER_FROM_IMPORT = oldValue; + } + } + private void doTest() { final String path = "/completion/className/" + getTestName(true); myFixture.copyDirectoryToProject(path, ""); diff --git a/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java b/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java index 956b7867b150..436b3860bd6d 100644 --- a/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java +++ b/python/testSrc/com/jetbrains/python/PyFindUsagesTest.java @@ -127,6 +127,11 @@ public class PyFindUsagesTest extends PyTestCase { } } + public void testNameShadowing() { // PY-6241 + final Collection usages = myFixture.testFindUsages("findUsages/NameShadowing.py"); + assertEquals(2, usages.size()); + } + private Collection findMultiFileUsages(String filename) { final String testName = getTestName(false); myFixture.copyDirectoryToProject("findUsages/" + testName, ""); diff --git a/python/testSrc/com/jetbrains/python/PyFormatterTest.java b/python/testSrc/com/jetbrains/python/PyFormatterTest.java index 83e638c664f9..f17d0a2ecd63 100644 --- a/python/testSrc/com/jetbrains/python/PyFormatterTest.java +++ b/python/testSrc/com/jetbrains/python/PyFormatterTest.java @@ -290,6 +290,16 @@ public class PyFormatterTest extends PyTestCase { doTest(); } + public void testLongWith() { // PY-8743 + PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), LanguageLevel.PYTHON27); + try { + doTest(); + } + finally { + PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), null); + } + } + private void doTest() { myFixture.configureByFile("formatter/" + getTestName(true) + ".py"); ApplicationManager.getApplication().runWriteAction(new Runnable() { diff --git a/python/testSrc/com/jetbrains/python/PyResolveTest.java b/python/testSrc/com/jetbrains/python/PyResolveTest.java index b79ca31463df..10150deef82d 100644 --- a/python/testSrc/com/jetbrains/python/PyResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyResolveTest.java @@ -521,4 +521,8 @@ public class PyResolveTest extends PyResolveTestCase { assertEquals("foo", res.getName()); assertInstanceOf(res.getParent(), PyAugAssignmentStatement.class); } + + public void testGeneratorShadowing() { // PY-8725 + assertResolvesTo(PyFunction.class, "_"); + } } diff --git a/python/testSrc/com/jetbrains/python/PyTypeTest.java b/python/testSrc/com/jetbrains/python/PyTypeTest.java index 87a250a2ddf1..d023461516fe 100644 --- a/python/testSrc/com/jetbrains/python/PyTypeTest.java +++ b/python/testSrc/com/jetbrains/python/PyTypeTest.java @@ -220,7 +220,7 @@ public class PyTypeTest extends PyTestCase { " return x\n" + "expr = f(1, 2)\n"; PyExpression expr = parseExpr(text); - PyType t = expr.getType(TypeEvalContext.slow()); + PyType t = TypeEvalContext.slow().getType(expr); assertTrue(PyTypeChecker.isUnknown(t)); doTest("int", text); } @@ -234,7 +234,7 @@ public class PyTypeTest extends PyTestCase { " return foo(x)\n" + "expr = xyzzy(a, b)"; PyExpression expr = parseExpr(text); - PyType t = expr.getType(TypeEvalContext.slow()); + PyType t = TypeEvalContext.slow().getType(expr); assertInstanceOf(t, PyTypeReference.class); } @@ -297,7 +297,7 @@ public class PyTypeTest extends PyTestCase { PyExpression expr = parseExpr("def foo(x): return foo(x)\n" + "expr = foo(1)"); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType actual = expr.getType(context); + PyType actual = context.getType(expr); assertFalse(actual.isBuiltin(context)); } @@ -311,7 +311,7 @@ public class PyTypeTest extends PyTestCase { "\n" + "expr = f(1)\n"); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType actual = expr.getType(context); + PyType actual = context.getType(expr); assertNotNull(actual); assertEquals("int", actual.getName()); } @@ -326,7 +326,7 @@ public class PyTypeTest extends PyTestCase { "\n" + "expr = f(1)\n"); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType actual = expr.getType(context); + PyType actual = context.getType(expr); assertNotNull(actual); assertEquals("int", actual.getName()); } @@ -336,7 +336,7 @@ public class PyTypeTest extends PyTestCase { PyExpression expr = parseExpr("def f():\n" + " expr = yield 2\n"); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType actual = expr.getType(context); + PyType actual = context.getType(expr); assertNull(actual); } @@ -381,7 +381,7 @@ public class PyTypeTest extends PyTestCase { "x = f()\n" + "expr = x.start\n"); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType actual = expr.getType(context); + PyType actual = context.getType(expr); assertNull(actual); } @@ -393,7 +393,7 @@ public class PyTypeTest extends PyTestCase { "x = C()\n" + "expr = type(x)\n"); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType type = expr.getType(context); + PyType type = context.getType(expr); assertInstanceOf(type, PyClassType.class); assertTrue("Got instance type instead of class type", ((PyClassType)type).isDefinition()); } @@ -405,7 +405,7 @@ public class PyTypeTest extends PyTestCase { "\n" + "expr = type(C)\n"); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType type = expr.getType(context); + PyType type = context.getType(expr); assertInstanceOf(type, PyClassType.class); assertEquals(type.getName(), "type"); } @@ -415,7 +415,7 @@ public class PyTypeTest extends PyTestCase { PyExpression expr = parseExpr("def f(x):\n" + " expr = type(x)\n"); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType type = expr.getType(context); + PyType type = context.getType(expr); assertNull(type); } @@ -445,7 +445,7 @@ public class PyTypeTest extends PyTestCase { public void testListComprehensionType() { final PyExpression expr = parseExpr("expr = [str(x) for x in range(10)]\n"); final TypeEvalContext context = TypeEvalContext.slow().withTracing(); - final PyType type = expr.getType(context); + final PyType type = context.getType(expr); assertNotNull(type); assertInstanceOf(type, PyCollectionType.class); assertEquals(type.getName(), "list"); @@ -459,7 +459,7 @@ public class PyTypeTest extends PyTestCase { public void testGeneratorComprehensionType() { final PyExpression expr = parseExpr("expr = (str(x) for x in range(10))\n"); final TypeEvalContext context = TypeEvalContext.slow().withTracing(); - final PyType type = expr.getType(context); + final PyType type = context.getType(expr); assertNotNull(type); assertInstanceOf(type, PyCollectionType.class); assertEquals(type.getName(), "__generator"); @@ -491,7 +491,7 @@ public class PyTypeTest extends PyTestCase { private void doTest(final String expectedType, final String text) { PyExpression expr = parseExpr(text); TypeEvalContext context = TypeEvalContext.slow().withTracing(); - PyType actual = expr.getType(context); + PyType actual = context.getType(expr); PyType expected = PyTypeParser.getTypeByName(expr, expectedType); if (expected != null) { assertNotNull(context.printTrace(), actual); diff --git a/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java b/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java index a612edb362b5..78950a0aa6ab 100644 --- a/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java +++ b/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java @@ -106,7 +106,8 @@ public class PythonAllTestsSuite { PyStatementListTest.class, PyChangeSignatureTest.class, PyCommenterTest.class, - PyRegexpTest.class + PyRegexpTest.class, + PyAddImportTest.class }; public static TestSuite suite() { diff --git a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java index 044c6208fc44..c08b75db28d6 100644 --- a/python/testSrc/com/jetbrains/python/PythonCompletionTest.java +++ b/python/testSrc/com/jetbrains/python/PythonCompletionTest.java @@ -613,4 +613,18 @@ public class PythonCompletionTest extends PyTestCase { doTestByText("def foo(**)"); myFixture.checkResult("def foo(**kwargs)"); } + + public void testLocalImportedModule() { // PY-3668 + myFixture.copyDirectoryToProject("completion/py3668", ""); + myFixture.configureByFile("py3668.py"); + myFixture.completeBasic(); + myFixture.checkResultByFile("completion/py3668/py3668.after.py"); + } + + public void testDuplicateDunderAll() { // PY-6483 + doTestByText("VAR = 1\nVAR = 2\n__all__ = ['']"); + myFixture.checkResult("VAR = 1\n" + + "VAR = 2\n" + + "__all__ = ['VAR']"); + } }