Merge branch 'master' of git.labs.intellij.net:idea/ultimate

This commit is contained in:
Dmitry Cheryasov
2010-04-08 21:09:44 +03:00
29 changed files with 1027 additions and 234 deletions
+74 -4
View File
@@ -1,5 +1,4 @@
# encoding: utf-8
import re
"""
This thing tries to restore public interface of objects that don't have a python
source: C extensions and built-in objects. It does not reimplement the
@@ -24,6 +23,7 @@ import os
import string
import stat
import types
import atexit
#import __builtin__
try:
@@ -33,6 +33,9 @@ except ImportError:
import re
if sys.platform == 'cli':
import clr
string_mod = string
version = (
@@ -161,6 +164,31 @@ def sortedNoCase(p_array):
return p_array
def cleanup(value):
result = ''
for c in value:
if c == '\n': result += '\\n'
elif c == '\r': result += '\\r'
elif c < ' ' or c > chr(127): result += '?'
else: result += c
return result
# http://blogs.msdn.com/curth/archive/2009/03/29/an-ironpython-profiler.aspx
def print_profile():
data = []
data.extend(clr.GetProfilerData())
data.sort(lambda x, y: -cmp(x.InclusiveTime, y.InclusiveTime))
for p in data:
print '%s\t%d\t%d\t%d' % (p.Name, p.InclusiveTime, p.ExclusiveTime, p.Calls)
def is_clr_type(t):
if not t: return False
try:
clr.GetClrType(t)
return True
except TypeError:
return False
_prop_types = [type(property())]
try: _prop_types.append(types.GetSetDescriptorType)
except: pass
@@ -613,7 +641,7 @@ class ModuleRedeclarator(object):
else:
# a forward / circular declaration happens
notice = ""
s = repr(p_value)
s = cleanup(repr(p_value))
if found_name:
if found_name == as_name:
notice = " # (!) real value is " + s
@@ -739,6 +767,27 @@ class ModuleRedeclarator(object):
spec.append("**" + kwarg)
return flatten(spec)
def restoreClr(self, p_func, p_name, p_class):
"""Restore the function signature by the CLR type signature"""
clr_type = clr.GetClrType(p_class)
if p_name == '__new__':
methods = clr_type.GetConstructors()
if not methods:
return p_name + '(*args) # could not find CLR constructor'
else:
methods = [m for m in clr_type.GetMethods() if m.Name == p_name]
if not methods:
return p_name + '(*args) # could not find CLR method'
method = methods[0]
for overload in methods[1:]:
if len(overload.GetParameters()) < len(method.GetParameters()): method = overload
params = [p.Name for p in method.GetParameters()]
if not method.IsStatic:
params = ['self'] + params
if len(methods) > 1:
params.append("*___args")
return p_name + '(' + ', '.join(params) + ')'
def redoFunction(self, p_func, p_name, indent, p_class=None, p_modname=None):
"""
Restore function argument list as best we can.
@@ -771,6 +820,7 @@ class ModuleRedeclarator(object):
#self.out("@staticmethod # known case of __new__", indent)
deco = "staticmethod"
deco_comment = " # known case of __new__"
if deco and HAS_DECORATORS:
self.out("@" + deco + deco_comment, indent)
if inspect and inspect.isfunction(p_func):
@@ -780,7 +830,10 @@ class ModuleRedeclarator(object):
spec, sig_note = self.restorePredefinedBuiltin(classname, p_name)
self.out("def " + spec + ": # " + sig_note, indent)
self.outDocAttr(p_func, indent+1, p_class)
elif sys.platform == 'cli' and is_clr_type(p_class):
spec = self.restoreClr(p_func, p_name, p_class)
self.out("def " + spec + ":", indent)
self.outDocAttr(p_func, indent+1, p_class)
else:
# __doc__ is our best source of arglist
sig_note = "real signature unknown"
@@ -1042,8 +1095,10 @@ if __name__ == "__main__":
-q -- quiet, do not print anything on stdout. Errors still go to stderr.
-u -- update, only recreate skeletons for newer files, and skip unchanged.
-x -- die on exceptions with a stacktrace; only for debugging.
-c modules -- import CLR assemblies with specified names
-p -- run CLR profiler
"""
opts, fnames = getopt(sys.argv[1:], "d:hbqux")
opts, fnames = getopt(sys.argv[1:], "d:hbquxc:p")
opts = dict(opts)
if not opts or '-h' in opts:
print(helptext)
@@ -1066,6 +1121,18 @@ if __name__ == "__main__":
names.remove('__main__') # we don't want ourselves processed
else:
doing_builtins = False
if sys.platform == 'cli':
refs = opts.get('-c', '')
if refs:
for ref in refs.split(';'): clr.AddReferenceByPartialName(ref)
if '-p' in opts:
atexit.register(print_profile)
from System import DateTime
start = DateTime.Now
# go on
for name in names:
if not quiet:
@@ -1126,3 +1193,6 @@ if __name__ == "__main__":
raise
else:
continue
if sys.platform == 'cli':
print "Generation completed in " + str((DateTime.Now - start).TotalMilliseconds) + " ms"
+225
View File
@@ -0,0 +1,225 @@
try:
from code import InteractiveConsole
except ImportError:
from pydevconsole_code_for_ironpython import InteractiveConsole
import os
import sys
try:
False
True
except NameError: # version < 2.3 -- didn't have the True/False builtins
import __builtin__
setattr(__builtin__, 'True', 1) #Python 3.0 does not accept __builtin__.True = 1 in its syntax
setattr(__builtin__, 'False', 0)
try:
try:
import xmlrpclib
except ImportError:
import xmlrpc.client as xmlrpclib
except ImportError:
import _pydev_xmlrpclib as xmlrpclib
#=======================================================================================================================
# StdIn
#=======================================================================================================================
class StdIn:
'''
Object to be added to stdin (to emulate it as non-blocking while the next line arrives)
'''
def __init__(self, interpreter, host, client_port):
self.interpreter = interpreter
self.client_port = client_port
self.host = host
def readline(self, *args, **kwargs): #@UnusedVariable
#Ok, callback into the client to see get the new input
server = xmlrpclib.Server('http://%s:%s' % (self.host, self.client_port))
return server.RequestInput()
def isatty(self):
return False #not really a file
def write(self, *args, **kwargs):
pass #not available StdIn (but it can be expected to be in the stream interface)
def flush(self, *args, **kwargs):
pass #not available StdIn (but it can be expected to be in the stream interface)
#in the interactive interpreter, a read and a readline are the same.
read = readline
#=======================================================================================================================
# InterpreterInterface
#=======================================================================================================================
class InterpreterInterface:
'''
The methods in this class should be registered in the xml-rpc server.
'''
def __init__(self, host, client_port):
self.client_port = client_port
self.host = host
self.namespace = {}
self.interpreter = InteractiveConsole(self.namespace)
def addExec(self, line):
#f_opened = open('c:/temp/a.txt', 'a')
#f_opened.write(line+'\n')
original_in = sys.stdin
try:
help = None
if 'pydoc' in sys.modules:
pydoc = sys.modules['pydoc'] #Don't import it if it still is not there.
if hasattr(pydoc, 'help'):
#You never know how will the API be changed, so, let's code defensively here
help = pydoc.help
if not hasattr(help, 'input'):
help = None
except:
#Just ignore any error here
pass
sys.stdin = StdIn(self, self.host, self.client_port)
if help is not None:
#This will enable the help() function to work.
help.input = sys.stdin
try:
more = self.interpreter.push(line)
finally:
if help is not None:
help.input = original_in
sys.stdin = original_in
#it's always false at this point
need_input = False
return more, need_input
def getCompletions(self, text):
from _completer import Completer
completer = Completer(self.namespace, None)
return completer.complete(text)
def getDescription(self, text):
obj = None
if '.' not in text:
try:
obj = self.namespace[text]
except KeyError:
return ''
else:
try:
splitted = text.split('.')
obj = self.namespace[splitted[0]]
for t in splitted[1:]:
obj = getattr(obj, t)
except:
return ''
if obj is not None:
try:
if sys.platform.startswith("java"):
#Jython
doc = obj.__doc__
if doc is not None:
return doc
import jyimportsTipper
is_method, infos = jyimportsTipper.ismethod(obj)
ret = ''
if is_method:
for info in infos:
ret += info.getAsDoc()
return ret
else:
#Python and Iron Python
import inspect #@UnresolvedImport
doc = inspect.getdoc(obj)
if doc is not None:
return doc
except:
pass
try:
#if no attempt succeeded, try to return repr()...
return repr(obj)
except:
try:
#otherwise the class
return str(obj.__class__)
except:
#if all fails, go to an empty string
return ''
def close(self):
sys.exit(0)
#=======================================================================================================================
# _DoExit
#=======================================================================================================================
def _DoExit(*args):
'''
We have to override the exit because calling sys.exit will only actually exit the main thread,
and as we're in a Xml-rpc server, that won't work.
'''
try:
import java.lang.System
java.lang.System.exit(1)
except ImportError:
if len(args) == 1:
os._exit(args[0])
else:
os._exit(0)
#=======================================================================================================================
# StartServer
#=======================================================================================================================
def StartServer(host, port, client_port):
#replace exit (see comments on method)
#note that this does not work in jython!!! (sys method can't be replaced).
sys.exit = _DoExit
try:
try:
from SimpleXMLRPCServer import SimpleXMLRPCServer
except ImportError:
from xmlrpc.server import SimpleXMLRPCServer
except ImportError:
from _pydev_SimpleXMLRPCServer import SimpleXMLRPCServer
interpreter = InterpreterInterface(host, client_port)
server = SimpleXMLRPCServer((host, port), logRequests=False)
server.register_function(interpreter.addExec)
server.register_function(interpreter.getCompletions)
server.register_function(interpreter.getDescription)
server.register_function(interpreter.close)
server.serve_forever()
#=======================================================================================================================
# main
#=======================================================================================================================
if __name__ == '__main__':
port, client_port = sys.argv[1:3]
StartServer('localhost', int(port), int(client_port))
+1
View File
@@ -37,6 +37,7 @@
<orderEntry type="module" module-name="RegExpSupport" />
<orderEntry type="module" module-name="yaml" />
<orderEntry type="library" name="microba" level="project" />
<orderEntry type="library" name="XmlRPC" level="project" />
</component>
<component name="copyright">
<Base>
@@ -316,6 +316,11 @@
text="Run Python Console..." description="Allows to quickly run Python console">
<add-to-group group-id="ToolsMenu" anchor="last"/>
</action>
<action id="com.jetbrains.python.console.RunPythonConsoleActionNew"
class="com.jetbrains.python.console.RunPythonConsoleActionNew"
text="Run TRUE Python Console..." description="Allows to quickly run Python console">
<add-to-group group-id="ToolsMenu" anchor="last"/>
</action>
<action id="com.jetbrains.django.console.RunDjangoConsoleAction"
class="com.jetbrains.django.console.RunDjangoConsoleAction"
text="Run Django Console..." description="Allows to quickly run Django console">
@@ -0,0 +1,111 @@
package com.jetbrains.python.actions;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyImportReferenceImpl;
import com.jetbrains.python.sdk.IronPythonSdkFlavor;
import com.jetbrains.python.sdk.PythonSdkFlavor;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author yole
*/
public class GenerateBinaryStubsFix implements LocalQuickFix {
private String myQualifiedName;
private Sdk mySdk;
public GenerateBinaryStubsFix(PsiReference reference) {
myQualifiedName = getReferenceText(reference);
mySdk = getPythonSdk(reference);
}
private static String getReferenceText(PsiReference reference) {
PsiElement element = reference.getElement();
while (element.getParent() instanceof PyReferenceExpression) {
element = element.getParent();
}
return element.getText();
}
@NotNull
public String getName() {
return "Generate stubs for binary module " + myQualifiedName;
}
@NotNull
public String getFamilyName() {
return "GenerateBinaryStubs";
}
public void applyFix(@NotNull Project project, @NotNull final ProblemDescriptor descriptor) {
ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() {
public void run() {
List<String> assemblyRefs = collectAssemblyReferences(descriptor.getPsiElement().getContainingFile());
final String skeletonPath = PythonSdkType.findSkeletonsPath(mySdk);
PythonSdkType.generateSkeleton(mySdk.getHomePath(), skeletonPath, myQualifiedName, assemblyRefs);
final VirtualFile skeletonDir = LocalFileSystem.getInstance().findFileByPath(skeletonPath);
if (skeletonDir != null) {
skeletonDir.refresh(true, true);
}
}
}, "Generating stubs for binary module", false, project);
}
private List<String> collectAssemblyReferences(PsiFile file) {
if (!(PythonSdkFlavor.getFlavor(mySdk.getHomePath()) instanceof IronPythonSdkFlavor)) {
return Collections.emptyList();
}
final List<String> result = new ArrayList<String>();
file.accept(new PyRecursiveElementVisitor() {
@Override
public void visitPyCallExpression(PyCallExpression node) {
super.visitPyCallExpression(node);
if (node.isCalleeText("AddReference") || node.isCalleeText("AddReferenceByPartialName")) {
final PyExpression[] args = node.getArguments();
if (args.length == 1 && args [0] instanceof PyStringLiteralExpression) {
result.add(((PyStringLiteralExpression) args [0]).getStringValue());
}
}
}
});
return result;
}
public static boolean isApplicable(PsiReference ref) {
if (!(ref instanceof PyImportReferenceImpl)) {
return false;
}
final Sdk sdk = getPythonSdk(ref);
if (sdk == null) {
return false;
}
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdk.getHomePath());
if (flavor instanceof IronPythonSdkFlavor) {
return getReferenceText(ref).contains("System");
}
return false;
}
@Nullable
private static Sdk getPythonSdk(PsiReference ref) {
final Module module = ModuleUtil.findModuleForPsiElement(ref.getElement());
return module == null ? null : PythonSdkType.findPythonSdk(module);
}
}
@@ -4,9 +4,9 @@ import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.PyClass;
import com.jetbrains.python.psi.PyElementGenerator;
import com.jetbrains.python.psi.PyExpression;
@@ -31,7 +31,8 @@ public class TransformClassicClassQuickFix implements LocalQuickFix {
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement psiElement = descriptor.getPsiElement();
if (psiElement instanceof PyClass) {
psiElement = PsiTreeUtil.getParentOfType(psiElement, PyClass.class);
if (psiElement != null) {
PyClass pyClass = (PyClass) psiElement;
PyExpression[] superClassExpressions = pyClass.getSuperClassExpressions();
PyElementGenerator generator = PyElementGenerator.getInstance(project);
@@ -9,7 +9,6 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyTokenTypes;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.*;
import org.jetbrains.annotations.NotNull;
@@ -53,27 +52,12 @@ public class PySplitIfIntention extends BaseIntentionAction {
}
PyIfStatement ifStatement = PsiTreeUtil.getParentOfType(element, PyIfStatement.class);
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
StringBuilder builder = new StringBuilder();
builder.append("if ").append(element.getLeftExpression().getText()).append(":\n");
builder.append(" if ").append(element.getRightExpression().getText()).append(":");
appendStatements(ifStatement.getIfPart().getStatementList(), builder);
final PyIfPart[] elifParts = ifStatement.getElifParts();
for (PyIfPart elifPart: elifParts) {
builder.append("\n elif ").append(elifPart.getCondition().getText()).append(":");
appendStatements(elifPart.getStatementList(), builder);
}
final PyElsePart elsePart = ifStatement.getElsePart();
if (elsePart != null) {
builder.append("\n else:");
appendStatements(elsePart.getStatementList(), builder);
}
ifStatement.getIfPart().replace(elementGenerator.createFromText(PyIfStatement.class, builder.toString()));
}
private static void appendStatements(PyStatementList statementList, StringBuilder builder) {
for (PyStatement statement : statementList.getStatements()) {
builder.append("\n ").append(statement.getText());
}
PyIfStatement subIf = (PyIfStatement) ifStatement.copy();
subIf.getIfPart().getCondition().replace(element.getRightExpression());
ifStatement.getIfPart().getCondition().replace(element.getLeftExpression());
PyStatementList statementList = elementGenerator.createFromText(PyIfStatement.class, "if a:\n a = 1").getIfPart().getStatementList();
statementList.getStatements()[0].replace(subIf);
ifStatement.getIfPart().getStatementList().replace(statementList);
}
}
@@ -4,6 +4,7 @@ import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.process.ColoredProcessHandler;
import com.intellij.execution.process.ConsoleHighlighter;
import com.intellij.execution.process.OSProcessHandler;
import com.intellij.execution.process.ProcessOutputTypes;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
@@ -19,16 +20,16 @@ import java.util.regex.Pattern;
/**
* @author oleg
*/
class PyConsoleProcessHandler extends OSProcessHandler {
private final PyConsoleRunner myPyConsoleRunner;
public class PyConsoleProcessHandler extends OSProcessHandler {
private final Charset myCharset;
private final LanguageConsoleImpl myLanguageConsole;
public PyConsoleProcessHandler(final PyConsoleRunner pyConsoleRunner,
final Process process,
public PyConsoleProcessHandler(final Process process,
final LanguageConsoleImpl languageConsole,
final String commandLine,
final Charset charset) {
super(process, commandLine);
myPyConsoleRunner = pyConsoleRunner;
myLanguageConsole = languageConsole;
myCharset = charset;
}
@@ -60,27 +61,31 @@ class PyConsoleProcessHandler extends OSProcessHandler {
@Override
public void notifyTextAvailable(final String text, final Key attributes) {
final LanguageConsoleImpl languageConsole = myPyConsoleRunner.getLanguageConsole();
String string = processPrompts(languageConsole, StringUtil.convertLineSeparators(text));
String string = processPrompts(myLanguageConsole, StringUtil.convertLineSeparators(text));
processOutput(myLanguageConsole, string, attributes);
}
public static void processOutput(LanguageConsoleImpl console, String string, final Key attributes) {
final ConsoleViewContentType type =
attributes == ProcessOutputTypes.STDERR ? ConsoleViewContentType.ERROR_OUTPUT : ConsoleViewContentType.NORMAL_OUTPUT;
// Highlight output by pattern
Matcher matcher;
while ((matcher = CODE_ELEMENT_PATTERN.matcher(string)).find()) {
printToConsole(languageConsole, string.substring(0, matcher.start()), ConsoleViewContentType.NORMAL_OUTPUT);
printToConsole(console, string.substring(0, matcher.start()), type);
// Number group
if (matcher.group(1) != null) {
printToConsole(languageConsole, matcher.group(1), NUMBER_ATTRIBUTES);
printToConsole(console, matcher.group(1), NUMBER_ATTRIBUTES);
}
// String group
else if (matcher.group(6) != null) {
printToConsole(languageConsole, matcher.group(6), STRING_ATTRIBUTES);
printToConsole(console, matcher.group(6), STRING_ATTRIBUTES);
}
else {
printToConsole(languageConsole, matcher.group(), ConsoleViewContentType.NORMAL_OUTPUT);
printToConsole(console, matcher.group(), type);
}
string = string.substring(matcher.end());
}
printToConsole(languageConsole, string, ConsoleViewContentType.NORMAL_OUTPUT);
printToConsole(console, string, type);
}
private String processPrompts(final LanguageConsoleImpl languageConsole, String string) {
@@ -119,7 +124,7 @@ class PyConsoleProcessHandler extends OSProcessHandler {
final TextAttributes attributes = TextAttributes.merge(type.getAttributes(), ConsoleHighlighter.OUT.getDefaultAttributes());
ApplicationManager.getApplication().invokeLater(new Runnable() {
public void run() {
console.addToHistory(string, attributes);
console.printToHistory(string, attributes);
}
}, ModalityState.stateForComponent(console.getComponent()));
}
@@ -7,16 +7,11 @@ import com.intellij.execution.ExecutionManager;
import com.intellij.execution.Executor;
import com.intellij.execution.ExecutorRegistry;
import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.console.LanguageConsoleViewImpl;
import com.intellij.execution.executors.DefaultDebugExecutor;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.execution.filters.Filter;
import com.intellij.execution.process.*;
import com.intellij.execution.ui.RunContentDescriptor;
import com.intellij.execution.ui.RunContentManager;
import com.intellij.execution.ui.actions.CloseAction;
import com.intellij.ide.CommonActionsManager;
import com.intellij.lang.Language;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
@@ -38,16 +33,10 @@ import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.PsiFile;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.util.PairProcessor;
import com.jetbrains.django.run.ExecutionHelper;
import com.jetbrains.django.run.Runner;
import com.jetbrains.django.util.DjangoUtil;
import com.jetbrains.python.PythonLanguage;
import com.jetbrains.python.psi.LanguageLevel;
import com.jetbrains.python.psi.PyUtil;
import com.jetbrains.python.psi.types.PyModuleType;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -67,17 +56,17 @@ public class PyConsoleRunner {
private final String myConsoleTitle;
private OSProcessHandler myProcessHandler;
private final CommandLineArgumentsProvider myProvider;
private final String myWorkingDir;
protected final CommandLineArgumentsProvider myProvider;
protected final String myWorkingDir;
private PyLanguageConsoleView myConsoleView;
protected PyLanguageConsoleView myConsoleView;
private final ConsoleHistoryModel myHistory = new ConsoleHistoryModel();
private AnAction myRunAction;
private PyConsoleRunner(@NotNull final Project project,
public PyConsoleRunner(@NotNull final Project project,
@NotNull final String consoleTitle,
@NotNull final CommandLineArgumentsProvider provider,
@Nullable final String workingDir) throws ExecutionException {
@Nullable final String workingDir) {
myProject = project;
myConsoleTitle = consoleTitle;
myProvider = provider;
@@ -88,40 +77,27 @@ public class PyConsoleRunner {
@NotNull final String consoleTitle,
@NotNull final CommandLineArgumentsProvider provider,
@Nullable final String workingDir) {
final PyConsoleRunner consoleRunner = new PyConsoleRunner(project, consoleTitle, provider, workingDir);
try {
final PyConsoleRunner consoleRunner = createRunner(project, consoleTitle, provider, workingDir);
initAndRun(consoleRunner);
consoleRunner.initAndRun();
}
catch (ExecutionException e) {
ExecutionHelper.showErrors(project, Arrays.<Exception>asList(e), consoleTitle, null);
}
}
@NotNull
public static PyConsoleRunner createRunner(@NotNull final Project project,
@NotNull final String consoleTitle,
@NotNull final CommandLineArgumentsProvider provider,
@Nullable final String workingDir) throws ExecutionException {
return new PyConsoleRunner(project, consoleTitle, provider, workingDir);
}
public static void initAndRun(@NotNull final PyConsoleRunner runner) throws ExecutionException {
runner.init();
runner.doRun();
}
private void init() throws ExecutionException {
// add holder created
final Process process = Runner.createProcess(myWorkingDir, true, myProvider.getAdditionalEnvs(), myProvider.getArguments());
final Charset outputEncoding = EncodingManager.getInstance().getDefaultCharset();
myProcessHandler = new PyConsoleProcessHandler(this, process, getProviderCommandLine(), outputEncoding);
ProcessTerminatedListener.attach(myProcessHandler);
public void initAndRun() throws ExecutionException {
// Create Server process
final Process process = createProcess();
// Init console view
myConsoleView = new PyLanguageConsoleView(myProject, myConsoleTitle);
myProcessHandler = createProcessHandler(process);
ProcessTerminatedListener.attach(myProcessHandler);
// Set language level
for (Module module : ModuleManager.getInstance(myProject).getModules()) {
final Sdk pythonSdk = PythonSdkType.findPythonSdk(module);
@@ -138,7 +114,7 @@ public class PyConsoleRunner {
break;
}
}
myProcessHandler.addProcessListener(new ProcessAdapter() {
@Override
public void processTerminated(ProcessEvent event) {
@@ -191,6 +167,19 @@ public class PyConsoleRunner {
IdeFocusManager.getInstance(myProject).requestFocus(getLanguageConsole().getCurrentEditor().getContentComponent(), true);
}
});
// Run
myProcessHandler.startNotify();
}
@Nullable
protected Process createProcess() throws ExecutionException {
return Runner.createProcess(myWorkingDir, true, myProvider.getAdditionalEnvs(), myProvider.getArguments());
}
protected PyConsoleProcessHandler createProcessHandler(final Process process) {
final Charset outputEncoding = EncodingManager.getInstance().getDefaultCharset();
return new PyConsoleProcessHandler(process, myConsoleView.getConsole(), getProviderCommandLine(), outputEncoding);
}
private void registerActionShortcuts(final AnAction[] actions, final JComponent component) {
@@ -252,11 +241,9 @@ public class PyConsoleRunner {
return new AnAction[]{stopAction, closeAction, myRunAction, historyNextAction, historyPrevAction};
}
private void doRun() {
myProcessHandler.startNotify();
}
private static void sendInput(final String input, final Charset charset, final OutputStream outputStream) {
protected void sendInput(final String input) {
final Charset charset = myProcessHandler.getCharset();
final OutputStream outputStream = myProcessHandler.getProcessInput();
try {
byte[] bytes = input.getBytes(charset.name());
outputStream.write(bytes);
@@ -285,7 +272,7 @@ public class PyConsoleRunner {
myHistory.addToHistory(line);
}
final String text2send = line.length() == 0 ? "\n\n" : line + "\n";
sendInput(text2send, myProcessHandler.getCharset(), myProcessHandler.getProcessInput());
sendInput(text2send);
myConsoleView.inputSent(text2send);
}
@@ -0,0 +1,123 @@
package com.jetbrains.python.console;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.console.LanguageConsoleImpl;
import com.intellij.execution.process.*;
import com.intellij.execution.ui.ConsoleViewContentType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.encoding.EncodingManager;
import com.intellij.util.net.NetUtils;
import com.jetbrains.django.run.ExecutionHelper;
import com.jetbrains.django.run.Runner;
import com.jetbrains.django.util.DjangoUtil;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.console.pydev.ICallback;
import com.jetbrains.python.console.pydev.InterpreterResponse;
import com.jetbrains.python.console.pydev.PydevConsoleCommunication;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
/**
* @author oleg
*/
public class PydevConsoleRunner extends PyConsoleRunner {
private final int[] myPorts;
private PydevConsoleCommunication myPydevConsoleCommunication;
protected PydevConsoleRunner(@NotNull final Project project,
@NotNull final String consoleTitle,
@NotNull final CommandLineArgumentsProvider provider,
@Nullable final String workingDir,
int[] ports) {
super(project, consoleTitle, provider, workingDir);
myPorts = ports;
}
public static void run(@NotNull final Project project,
@NotNull final Module module,
@NotNull final Sdk sdk) {
final String consoleTitle = "TRUE console";
final int[] ports;
try {
// File "pydev/pydevconsole.py", line 223, in <module>
// port, client_port = sys.argv[1:3]
ports = NetUtils.findAvailableSocketPorts(2);
}
catch (IOException e) {
ExecutionHelper.showErrors(project, Arrays.<Exception>asList(e), consoleTitle, null);
return;
}
final ArrayList<String> args = new ArrayList<String>(Arrays.asList(sdk.getHomePath(), "-u", PythonHelpersLocator.getHelperPath("pydev/pydevconsole.py")));
for (int port : ports) {
args.add(String.valueOf(port));
}
final CommandLineArgumentsProvider provider = new CommandLineArgumentsProvider() {
public String[] getArguments() {
return args.toArray(new String[args.size()]);
}
public boolean passParentEnvs() {
return false;
}
public Map<String, String> getAdditionalEnvs() {
return Collections.emptyMap();
}
};
final PydevConsoleRunner consoleRunner = new PydevConsoleRunner(project, consoleTitle, provider, DjangoUtil.getProjectRoot(module), ports);
try {
consoleRunner.initAndRun();
}
catch (ExecutionException e) {
ExecutionHelper.showErrors(project, Arrays.<Exception>asList(e), consoleTitle, null);
}
}
@Override
protected Process createProcess() throws ExecutionException {
final Process server = Runner.createProcess(myWorkingDir, true, myProvider.getAdditionalEnvs(), myProvider.getArguments());
try {
myPydevConsoleCommunication = new PydevConsoleCommunication(getProject(), myPorts[0], server, myPorts[1]);
}
catch (Exception e) {
throw new ExecutionException(e.getMessage());
}
return server;
}
@Override
public void initAndRun() throws ExecutionException {
super.initAndRun();
sendInput("import sys; print('Python %s on %s' % (sys.version, sys.platform))\n");
}
@Override
protected void sendInput(final String input) {
if (myPydevConsoleCommunication != null){
myPydevConsoleCommunication.execInterpreter(input, new ICallback<Object, InterpreterResponse>() {
public Object call(final InterpreterResponse interpreterResponse) {
final LanguageConsoleImpl console = myConsoleView.getConsole();
// TODO[oleg] More sophisticated callback required!
// At least this one works!
if (!StringUtil.isEmpty(interpreterResponse.err)){
PyConsoleProcessHandler.processOutput(console, interpreterResponse.err, ProcessOutputTypes.STDERR);
} else {
PyConsoleProcessHandler.processOutput(console, interpreterResponse.out, ProcessOutputTypes.STDOUT);
}
return null;
}
});
}
}
}
@@ -0,0 +1,64 @@
package com.jetbrains.python.console;
import com.intellij.execution.process.CommandLineArgumentsProvider;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.util.IconLoader;
import com.jetbrains.django.util.DjangoUtil;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.console.PydevConsoleRunner;
import com.jetbrains.python.sdk.PythonSdkType;
import java.util.Collections;
import java.util.Map;
/**
* @author oleg
*/
public class RunPythonConsoleActionNew extends AnAction implements DumbAware {
public RunPythonConsoleActionNew() {
super();
getTemplatePresentation().setIcon(IconLoader.getIcon("/com/jetbrains/python/python.png"));
}
@Override
public void update(final AnActionEvent e) {
e.getPresentation().setVisible(false);
e.getPresentation().setEnabled(false);
final Project project = e.getData(LangDataKeys.PROJECT);
if (project != null){
for (Module module : ModuleManager.getInstance(project).getModules()) {
e.getPresentation().setVisible(true);
if (PythonSdkType.findPythonSdk(module) != null){
e.getPresentation().setEnabled(true);
break;
}
}
}
}
public void actionPerformed(final AnActionEvent e) {
final Project project = e.getData(LangDataKeys.PROJECT);
assert project != null : "Project is null";
Sdk sdk = null;
Module module = null;
for (Module m : ModuleManager.getInstance(project).getModules()) {
module = m;
sdk = PythonSdkType.findPythonSdk(module);
if (sdk != null){
break;
}
}
assert module != null : "Module is null";
assert sdk != null : "Sdk is null";
PydevConsoleRunner.run(project, module, sdk);
}
}
@@ -22,10 +22,12 @@ import com.jetbrains.python.run.AbstractPythonRunConfiguration;
import com.jetbrains.python.run.CommandLinePatcher;
import com.jetbrains.python.run.PythonCommandLineState;
import com.jetbrains.python.run.PythonRunConfiguration;
import com.jetbrains.python.sdk.PythonSdkFlavor;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Collection;
/**
* @author yole
@@ -66,6 +68,13 @@ public class PyDebugRunner extends GenericProgramRunner {
// script name is the last parameter; all other params are for python interpreter; insert just before name
final ParametersList parameters_list = commandLine.getParametersList();
int parameter_offset = pyState.getInterpreterOptionsCount();
final PythonSdkFlavor flavor = pyState.getConfig().getSdkFlavor();
if (flavor != null) {
final Collection<String> options = flavor.getExtraDebugOptions();
for (String option : options) {
parameters_list.addAt(parameter_offset++, option);
}
}
for (int i = 0; i < args.length; i++) {
parameters_list.addAt(i + parameter_offset, args[i]);
}
@@ -16,10 +16,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Consumer;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.PyNames;
import com.jetbrains.python.actions.AddFieldQuickFix;
import com.jetbrains.python.actions.AddImportAction;
import com.jetbrains.python.actions.AddMethodQuickFix;
import com.jetbrains.python.actions.ImportFromExistingFix;
import com.jetbrains.python.actions.*;
import com.jetbrains.python.codeInsight.PyCodeInsightSettings;
import com.jetbrains.python.psi.*;
import com.jetbrains.python.psi.impl.PyBuiltinCache;
@@ -373,6 +370,9 @@ public class PyUnresolvedReferencesInspection extends LocalInspectionTool {
hl_type = ProblemHighlightType.LIKE_UNKNOWN_SYMBOL;
}
if (GenerateBinaryStubsFix.isApplicable(reference)) {
actions.add(new GenerateBinaryStubsFix(reference));
}
addPluginQuickFixes(reference, actions);
PsiElement point = node.getLastChild(); // usually the identifier at the end of qual ref
@@ -38,6 +38,13 @@ public interface PyCallExpression extends PyExpression {
@Nullable
PyMarkedFunction resolveCallee();
/**
* Checks if the unqualified name of the callee matches the specified text.
*
* @param name the text to check
* @return true if matches, false otherwise
*/
boolean isCalleeText(@NotNull String name);
/**
* Couples function with a flag describing the way it is called.
@@ -49,6 +49,14 @@ public class PyCallExpressionImpl extends PyElementImpl implements PyCallExpress
return PyCallExpressionHelper.resolveCallee(this);
}
public boolean isCalleeText(@NotNull String name) {
final PyExpression callee = getCallee();
if (!(callee instanceof PyReferenceExpression)) {
return false;
}
return name.equals(((PyReferenceExpression)callee).getReferencedName());
}
@Override
public String toString() {
return "PyCallExpression: " + PyUtil.getReadableRepr(getCallee(), true); //or: getCalledFunctionReference().getReferencedName();
@@ -102,6 +102,14 @@ public class PyDecoratorImpl extends PyPresentableElementImpl<PyDecoratorStub> i
return callee;
}
public boolean isCalleeText(@NotNull String name) {
final PyExpression callee = getCallee();
if (!(callee instanceof PyReferenceExpression)) {
return false;
}
return name.equals(((PyReferenceExpression)callee).getReferencedName());
}
@Override
public String toString() {
return "PyDecorator: @" + PyUtil.getReadableRepr(getCallee(), true); //getCalledFunctionReference().getReferencedName();
@@ -531,6 +531,9 @@ public class ResolveImportUtil {
public boolean visitRoot(final VirtualFile root) {
PsiElement module = root.isDirectory() ? psimgr.findDirectory(root) : psimgr.findFile(root);
for (String component : qualifiedName.getComponents()) {
if (component == null) {
return true;
}
module = resolveChild(module, component, foothold_file, false); // only files, we want a module
}
if (module != null) {
@@ -14,6 +14,7 @@ import com.intellij.openapi.util.JDOMExternalizerUtil;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.sdk.PythonSdkFlavor;
import com.jetbrains.python.sdk.PythonSdkType;
import org.jdom.Element;
import org.jetbrains.annotations.Nullable;
@@ -108,6 +109,12 @@ public abstract class AbstractPythonRunConfiguration extends ModuleBasedConfigur
return PythonSdkType.getInterpreterPath(sdkHome);
}
@Nullable
public PythonSdkFlavor getSdkFlavor() {
final String path = getInterpreterPath();
return path == null ? null : PythonSdkFlavor.getFlavor(path);
}
public void readExternal(Element element) throws InvalidDataException {
super.readExternal(element);
myInterpreterOptions = JDOMExternalizerUtil.readField(element, "INTERPRETER_OPTIONS");
@@ -0,0 +1,31 @@
package com.jetbrains.python.sdk;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
/**
* @author yole
*/
public class IronPythonSdkFlavor extends PythonSdkFlavor {
private IronPythonSdkFlavor() {
}
public static IronPythonSdkFlavor INSTANCE = new IronPythonSdkFlavor();
@Override
public boolean isValidSdkHome(String path) {
final String name = new File(path).getName();
return name.equals("ipy.exe") || name.equals("ipy64.exe");
}
@Override
public String getVersionString(String sdkHome) {
return "IronPython " + getVersionFromOutput(sdkHome, "-V", "\\w+ ([0-9\\.]+).*", true);
}
@Override
public Collection<String> getExtraDebugOptions() {
return Collections.singletonList("-X:Frames");
}
}
@@ -0,0 +1,26 @@
package com.jetbrains.python.sdk;
import com.intellij.openapi.util.io.FileUtil;
import java.io.File;
/**
* @author yole
*/
public class JythonSdkFlavor extends PythonSdkFlavor {
private JythonSdkFlavor() {
}
public static JythonSdkFlavor INSTANCE = new JythonSdkFlavor();
@Override
public boolean isValidSdkHome(String path) {
File file = new File(path);
return file.isFile() && FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("jython");
}
@Override
public String getVersionString(String sdkHome) {
return getVersionFromOutput(sdkHome, "--version", "(Jython \\S+) on .*", false);
}
}
@@ -0,0 +1,46 @@
package com.jetbrains.python.sdk;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import java.util.ArrayList;
import java.util.List;
/**
* @author yole
*/
public class MacPythonSdkFlavor extends PythonSdkFlavor {
private MacPythonSdkFlavor() {
}
public static MacPythonSdkFlavor INSTANCE = new MacPythonSdkFlavor();
@Override
public List<String> suggestHomePaths() {
List<String> candidates = new ArrayList<String>();
final String pythonPath = "/Library/Frameworks/Python.framework/Versions";
VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(pythonPath);
if (rootVDir != null) {
for (VirtualFile dir : rootVDir.getChildren()) {
final String dir_name = dir.getName().toLowerCase();
if (dir.isDirectory()) {
// TODO why would Jython be ever installed under /Library/Frameworks?
if ("Current".equals(dir_name) || dir_name.startsWith("2") || dir_name.startsWith("3") || dir_name.startsWith("jython")) {
VirtualFile bin_dir = dir.findChild("bin");
if (bin_dir != null && bin_dir.isDirectory()) {
VirtualFile python_exe = dir.findChild("python");
if (python_exe != null) candidates.add(python_exe.getPath());
python_exe = dir.findChild("jython"); // maybe it's in bin/
if (python_exe != null) candidates.add(python_exe.getPath());
}
else {
VirtualFile python_exe = dir.findChild("jython"); // maybe it's not in bin/
if (python_exe != null) candidates.add(python_exe.getPath());
}
}
}
}
}
return candidates;
}
}
@@ -0,0 +1,78 @@
package com.jetbrains.python.sdk;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
/**
* @author yole
*/
public abstract class PythonSdkFlavor {
public List<String> suggestHomePaths() {
return Collections.emptyList();
}
public static List<PythonSdkFlavor> getApplicableFlavors() {
List<PythonSdkFlavor> result = new ArrayList<PythonSdkFlavor>();
if (SystemInfo.isWindows) {
result.add(WinPythonSdkFlavor.INSTANCE);
}
else if (SystemInfo.isMac) {
result.add(MacPythonSdkFlavor.INSTANCE);
}
else if (SystemInfo.isUnix) {
result.add(UnixPythonSdkFlavor.INSTANCE);
}
result.add(JythonSdkFlavor.INSTANCE);
result.add(IronPythonSdkFlavor.INSTANCE);
return result;
}
@Nullable
public static PythonSdkFlavor getFlavor(String sdkPath) {
for (PythonSdkFlavor flavor : getApplicableFlavors()) {
if (flavor.isValidSdkHome(sdkPath)) {
return flavor;
}
}
return null;
}
/**
* Checks if the path is the name of a Python interpreter of this flavor.
*
* @param path path to check.
* @return true if paths points to a valid home.
*/
public boolean isValidSdkHome(String path) {
File file = new File(path);
return file.isFile() && FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("python");
}
public String getVersionString(String sdkHome) {
return getVersionFromOutput(sdkHome, "-V", "(Python \\S+).*", false);
}
protected static String getVersionFromOutput(String sdkHome, String version_opt, String version_regexp, boolean stdout) {
Pattern pattern = Pattern.compile(version_regexp);
String run_dir = new File(sdkHome).getParent();
final ProcessOutput process_output = SdkUtil.getProcessOutput(run_dir, new String[]{sdkHome, version_opt});
if (process_output.getExitCode() != 0) {
throw new RuntimeException(process_output.getStderr() + " (exit code " + process_output.getExitCode() + ")");
}
final List<String> lines = stdout ? process_output.getStdoutLines() : process_output.getStderrLines();
return SdkUtil.getFirstMatch(lines, pattern);
}
public Collection<String> getExtraDebugOptions() {
return Collections.emptyList();
}
}
@@ -48,11 +48,7 @@ import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.*;
import static com.jetbrains.python.psi.PyUtil.sure;
@@ -63,7 +59,7 @@ public class PythonSdkType extends SdkType {
private static final Logger LOG = Logger.getInstance("#" + PythonSdkType.class.getName());
private static final String[] WINDOWS_EXECUTABLE_SUFFIXES = new String[]{"cmd", "exe", "bat", "com"};
static final int RUN_TIMEOUT = 30 * 1000; // 30 seconds per script invocation is plenty; anything more seems wrong (10 wasn't enough tho).
static final int RUN_TIMEOUT = 60 * 1000; // 60 seconds per script invocation is plenty; anything more seems wrong (10 wasn't enough tho).
public static PythonSdkType getInstance() {
return SdkType.findInstance(PythonSdkType.class);
@@ -99,8 +95,6 @@ public class PythonSdkType extends SdkType {
return PyBuiltinCache.BUILTIN_FILE;
}
@NonNls static final private String PYTHON_STR = "python";
@NonNls
@Nullable
public String suggestHomePath() {
@@ -109,49 +103,8 @@ public class PythonSdkType extends SdkType {
return findDigits(o1).compareTo(findDigits(o2));
}
});
if (SystemInfo.isWindows) {
findSubdirInstallations(candidates, "C:\\", PYTHON_STR, "python.exe");
findSubdirInstallations(candidates, "C:\\Program Files\\", PYTHON_STR, "python.exe");
findSubdirInstallations(candidates, "C:\\", "jython", "jython.bat");
}
else if (SystemInfo.isMac) {
final String pythonPath = "/Library/Frameworks/Python.framework/Versions";
VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(pythonPath);
if (rootVDir != null) {
for (VirtualFile dir : rootVDir.getChildren()) {
final String dir_name = dir.getName().toLowerCase();
if (dir.isDirectory()) {
if ("Current".equals(dir_name) || dir_name.startsWith("2") || dir_name.startsWith("3") || dir_name.startsWith("jython")) {
VirtualFile bin_dir = dir.findChild("bin");
if (bin_dir != null && bin_dir.isDirectory()) {
VirtualFile python_exe = dir.findChild(PYTHON_STR);
if (python_exe != null) candidates.add(python_exe.getPath());
python_exe = dir.findChild("jython"); // maybe it's in bin/
if (python_exe != null) candidates.add(python_exe.getPath());
}
else {
VirtualFile python_exe = dir.findChild("jython"); // maybe it's not in bin/
if (python_exe != null) candidates.add(python_exe.getPath());
}
}
}
}
}
}
else if (SystemInfo.isUnix) {
VirtualFile rootDir = LocalFileSystem.getInstance().findFileByPath("/usr/bin");
if (rootDir != null) {
VirtualFile[] suspects = rootDir.getChildren();
for (VirtualFile child : suspects) {
if (!child.isDirectory()) {
final String child_name = child.getName();
if (child_name.startsWith(PYTHON_STR) || child_name.startsWith("jython")) {
candidates.add(child.getPath());
}
}
}
candidates.add(rootDir.getPath());
}
for (PythonSdkFlavor flavor : PythonSdkFlavor.getApplicableFlavors()) {
candidates.addAll(flavor.suggestHomePaths());
}
if (candidates.size() > 0) {
@@ -174,20 +127,8 @@ public class PythonSdkType extends SdkType {
return s;
}
private static void findSubdirInstallations(TreeSet<String> candidates, String rootDir, String dir_prefix, String exe_name) {
VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath("C:\\");
if (rootVDir != null) {
for (VirtualFile dir : rootVDir.getChildren()) {
if (dir.isDirectory() && dir.getName().toLowerCase().startsWith(dir_prefix)) {
VirtualFile python_exe = dir.findChild(exe_name);
if (python_exe != null) candidates.add(python_exe.getPath());
}
}
}
}
public boolean isValidSdkHome(final String path) {
return isPythonSdkHome(path) || isJythonSdkHome(path);
return PythonSdkFlavor.getFlavor(path) != null;
}
@Override
@@ -225,29 +166,6 @@ public class PythonSdkType extends SdkType {
return result;
}
/**
* Checks if the path is the name of a Python intepreter.
*
* @param path path to check.
* @return true if paths points to a valid home.
*/
@NonNls
private static boolean isPythonSdkHome(final String path) {
File file = new File(path);
return file.isFile() && FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("python");
}
/**
* Checks if the path is the name of a Jython intepreter.
*
* @param path path to check.
* @return true if paths points to a valid home.
*/
private static boolean isJythonSdkHome(final String path) {
File file = new File(path);
return file.isFile() && FileUtil.getNameWithoutExtension(file).toLowerCase().startsWith("jython");
}
/**
* @param path where to look
* @return Python interpreter executable on the path, or null.
@@ -429,9 +347,8 @@ public class PythonSdkType extends SdkType {
}
}
// fix skeletons as needed
String url = findSkeletonsUrl(currentSdk);
if (url != null) {
final String path = VfsUtil.urlToPath(url);
final String path = findSkeletonsPath(currentSdk);
if (path != null) {
File stubs_dir = new File(path);
if (!stubs_dir.exists()) {
final ProgressManager progman = ProgressManager.getInstance();
@@ -441,7 +358,7 @@ public class PythonSdkType extends SdkType {
public void run(@NotNull final ProgressIndicator indicator) {
try {
generateBuiltinStubs(currentSdk.getHomePath(), path);
generateBinaryStubs(currentSdk.getHomePath(), path, indicator);
generateBinarySkeletons(currentSdk.getHomePath(), path, indicator);
}
catch (Exception e) {
LOG.error(e);
@@ -487,11 +404,11 @@ public class PythonSdkType extends SdkType {
}
@Nullable
public static String findSkeletonsUrl(Sdk sdk) {
public static String findSkeletonsPath(Sdk sdk) {
final String[] urls = sdk.getRootProvider().getUrls(BUILTIN_ROOT_TYPE);
for (String url : urls) {
if (url.contains(SKELETON_DIR_NAME)) {
return url;
return VfsUtil.urlToPath(url);
}
}
return null;
@@ -605,7 +522,7 @@ public class PythonSdkType extends SdkType {
// regenerate stubs, existing or not
final File stubs_dir = new File(stubs_path);
if (!stubs_dir.exists()) stubs_dir.mkdirs();
generateBinaryStubs(bin_path, stubs_path, indicator);
generateBinarySkeletons(bin_path, stubs_path, indicator);
}
}
@@ -639,28 +556,8 @@ public class PythonSdkType extends SdkType {
@Nullable
public String getVersionString(final String sdkHome) {
final String binaryPath = getInterpreterPath(sdkHome);
if (binaryPath == null) {
return null;
}
final boolean isJython = isJythonSdkHome(sdkHome);
@NonNls String version_regexp, version_opt;
if (isJython) {
version_regexp = "(Jython \\S+) on .*";
version_opt = "--version";
}
else { // CPython
version_regexp = "(Python \\S+).*";
version_opt = "-V";
}
Pattern pattern = Pattern.compile(version_regexp);
String run_dir = new File(binaryPath).getParent();
final ProcessOutput process_output = SdkUtil.getProcessOutput(run_dir, new String[]{binaryPath, version_opt});
if (process_output.getExitCode() != 0) {
throw new RuntimeException(process_output.getStderr() + " (exit code " + process_output.getExitCode() + ")");
}
String version = SdkUtil.getFirstMatch(process_output.getStderrLines(), pattern);
return version;
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(sdkHome);
return flavor != null ? flavor.getVersionString(sdkHome) : null;
}
@Nullable
@@ -685,7 +582,7 @@ public class PythonSdkType extends SdkType {
"-b", // for builtins
"-u", // for update-only mode
},
getVirtualEnvAdditionalEnv(binary_path), RUN_TIMEOUT
getVirtualEnvAdditionalEnv(binary_path), RUN_TIMEOUT*5
);
if (run_result.getExitCode() != 0) {
LOG.error(run_result.getStderr() + (run_result.isTimeout()? "\nTimed out" : "\nExit code " + run_result.getExitCode()));
@@ -700,8 +597,7 @@ public class PythonSdkType extends SdkType {
* @param stubsRoot where to put results (expected to exist).
* @param indicator ProgressIndicator to update, or null.
*/
public static void generateBinaryStubs(final String binaryPath, final String stubsRoot, ProgressIndicator indicator)
{
public static void generateBinarySkeletons(final String binaryPath, final String stubsRoot, ProgressIndicator indicator) {
if (indicator != null) {
indicator.setText("Generating skeletons of binary libs");
}
@@ -732,19 +628,7 @@ public class PythonSdkType extends SdkType {
indicator.setText2(modname);
}
LOG.info("Skeleton for " + modname);
final ProcessOutput gen_result = SdkUtil.getProcessOutput(
parent_dir,
new String[]{binaryPath, PythonHelpersLocator.getHelperPath(GENERATOR3), "-d", stubsRoot, modname},
getVirtualEnvAdditionalEnv(binaryPath),
RUN_TIMEOUT
);
if (gen_result.getExitCode() != 0) {
StringBuffer sb = new StringBuffer("Skeleton for ");
sb.append(modname).append(" failed. stderr: --");
for (String err_line : gen_result.getStderrLines()) sb.append(err_line).append("\n");
sb.append("--");
LOG.warn(sb.toString());
}
generateSkeleton(binaryPath, stubsRoot, modname, Collections.<String>emptyList());
}
}
}
@@ -758,6 +642,34 @@ public class PythonSdkType extends SdkType {
}
}
public static void generateSkeleton(String binaryPath, String stubsRoot, String modname, List<String> assemblyRefs) {
final String parent_dir = new File(binaryPath).getParent();
List<String> commandLine = new ArrayList<String>();
commandLine.add(binaryPath);
commandLine.add(PythonHelpersLocator.getHelperPath(GENERATOR3));
commandLine.add("-d");
commandLine.add(stubsRoot);
if (!assemblyRefs.isEmpty()) {
commandLine.add("-c");
commandLine.add(StringUtil.join(assemblyRefs, ";"));
}
commandLine.add(modname);
final ProcessOutput gen_result = SdkUtil.getProcessOutput(
parent_dir,
commandLine.toArray(new String[commandLine.size()]),
getVirtualEnvAdditionalEnv(binaryPath),
RUN_TIMEOUT*10
);
if (gen_result.getExitCode() != 0) {
StringBuffer sb = new StringBuffer("Skeleton for ");
sb.append(modname).append(" failed. stderr: --");
for (String err_line : gen_result.getStderrLines()) sb.append(err_line).append("\n");
sb.append("--");
LOG.warn(sb.toString());
}
}
public static List<Sdk> getAllSdks() {
return ProjectJdkTable.getInstance().getSdksOfType(getInstance());
}
@@ -6,7 +6,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import org.jetbrains.annotations.NotNull;
import java.io.*;
@@ -18,7 +18,7 @@ import java.util.List;
public class SkeletonVersionUpdater implements ProjectComponent {
private static final Logger LOG = Logger.getInstance("#com.jetbrains.python.sdk.SkeletonVersionUpdater");
public static int SKELETONS_VERSION = 2;
public static int SKELETONS_VERSION = 3;
public SkeletonVersionUpdater(StartupManager startupManager) {
startupManager.registerStartupActivity(new Runnable() {
@@ -30,10 +30,9 @@ public class SkeletonVersionUpdater implements ProjectComponent {
writeVersion(versionFile, SKELETONS_VERSION);
final List<Sdk> sdkList = PythonSdkType.getAllSdks();
for (Sdk sdk : sdkList) {
final String url = PythonSdkType.findSkeletonsUrl(sdk);
final String path = VfsUtil.urlToPath(url);
final String path = PythonSdkType.findSkeletonsPath(sdk);
PythonSdkType.generateBuiltinStubs(sdk.getHomePath(), path);
PythonSdkType.generateBinaryStubs(sdk.getHomePath(), path, ProgressManager.getInstance().getProgressIndicator());
PythonSdkType.generateBinarySkeletons(sdk.getHomePath(), path, ProgressManager.getInstance().getProgressIndicator());
}
}
}
@@ -0,0 +1,36 @@
package com.jetbrains.python.sdk;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import java.util.ArrayList;
import java.util.List;
/**
* @author yole
*/
public class UnixPythonSdkFlavor extends PythonSdkFlavor {
private UnixPythonSdkFlavor() {
}
public static UnixPythonSdkFlavor INSTANCE = new UnixPythonSdkFlavor();
@Override
public List<String> suggestHomePaths() {
List<String> candidates = new ArrayList<String>();
VirtualFile rootDir = LocalFileSystem.getInstance().findFileByPath("/usr/bin");
if (rootDir != null) {
VirtualFile[] suspects = rootDir.getChildren();
for (VirtualFile child : suspects) {
if (!child.isDirectory()) {
final String child_name = child.getName();
if (child_name.startsWith("python") || child_name.startsWith("jython")) {
candidates.add(child.getPath());
}
}
}
candidates.add(rootDir.getPath());
}
return candidates;
}
}
@@ -0,0 +1,42 @@
package com.jetbrains.python.sdk;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NonNls;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author yole
*/
public class WinPythonSdkFlavor extends PythonSdkFlavor {
@NonNls static final private String PYTHON_STR = "python";
public static WinPythonSdkFlavor INSTANCE = new WinPythonSdkFlavor();
private WinPythonSdkFlavor() {
}
@Override
public List<String> suggestHomePaths() {
List<String> candidates = new ArrayList<String>();
findSubdirInstallations(candidates, "C:\\", PYTHON_STR, "python.exe");
findSubdirInstallations(candidates, "C:\\Program Files\\", PYTHON_STR, "python.exe");
findSubdirInstallations(candidates, "C:\\", "jython", "jython.bat");
return candidates;
}
private static void findSubdirInstallations(Collection<String> candidates, String rootDir, String dir_prefix, String exe_name) {
VirtualFile rootVDir = LocalFileSystem.getInstance().findFileByPath(rootDir);
if (rootVDir != null) {
for (VirtualFile dir : rootVDir.getChildren()) {
if (dir.isDirectory() && dir.getName().toLowerCase().startsWith(dir_prefix)) {
VirtualFile python_exe = dir.findChild(exe_name);
if (python_exe != null) candidates.add(python_exe.getPath());
}
}
}
}
}
@@ -161,9 +161,12 @@ public class UnsupportedFeatures extends PyAnnotator {
getHolder().createWarningAnnotation(node,
"Integer literals do not support a trailing \'l\' or \'L\' in Python 3").registerFix(new RemoveTrailingLIntention());
}
if (text.length() > 1 && text.charAt(0) == '0' && (text.charAt(1) != 'o' || text.charAt(1) != 'b')) {
getHolder().createWarningAnnotation(node,
"Python 3 requires '0o' prefix for octal literals").registerFix(new ReplaceOctalNumericLiteralIntention());
if (text.length() > 1 && text.charAt(0) == '0') {
char c = Character.toLowerCase(text.charAt(1));
if (c != 'o' && c != 'b' && c != 'x') {
getHolder().createWarningAnnotation(node,
"Python 3 requires '0o' prefix for octal literals").registerFix(new ReplaceOctalNumericLiteralIntention());
}
}
}
}
@@ -3,6 +3,8 @@ print(<warning descr="<> is not supported in Python 3, use != instead">a <> 3</w
x = <warning descr="Method 'raw_input' has been removed, use 'input' instead">raw_input</warning>()
a = <warning descr="Integer literals do not support a trailing 'l' or 'L' in Python 3">123l</warning>
a = <warning descr="Python 3 requires '0o' prefix for octal literals">043</warning>
a = 0X43
a = 0b1
s = <warning descr="String literals do not support a leading 'u' or 'U' in Python 3">u"text"</warning>
<warning descr="Python 3 does not support this syntax">raise a, b, c</warning>
<warning descr="Python 3 does not support this syntax">raise a, b</warning>
@@ -1,6 +1,6 @@
<caret><warning descr="Old-style class">class A:
class <warning descr="Old-style class"><caret>A</warning>:
def foo(self):
pass
def bar(self):
pass</warning>
pass