diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index b737a3def8ff..7d9625093305 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -27,6 +27,8 @@ but seemingly no one uses them in C extensions yet anyway. VERSION = "1.99" # Must be a number-dot-number string, updated with each change that affects generated skeletons # Note: DON'T FORGET TO UPDATE! +VERSION_CONTROL_HEADER_FORMAT = '# from %s by generator %s' + import sys import os import string @@ -1789,8 +1791,7 @@ class ModuleRedeclarator(object): else: mod_name = " does not know its name" out(0, "# module ", p_name, mod_name) # line 2 - version_control_header_format = '# from %s by generator %s' - out(0, version_control_header_format % ( + out(0, VERSION_CONTROL_HEADER_FORMAT % ( self.mod_filename or getattr(self.module, "__file__", "(built-in)"), VERSION) ) # line 3 if p_name == BUILTIN_MOD_NAME and version[0] == 2 and version[1] >= 6: @@ -2115,7 +2116,7 @@ def buildOutputName(subdir, name): fname = target_name + ".py" return fname -def redoModule(name, out_name, mod_file_name, doing_builtins, imported_module_names): +def redoModule(name, outfile, mod_file_name, doing_builtins, imported_module_names): # gobject does 'del _gobject' in its __init__.py, so the chained attribute lookup code # fails to find 'gobject._gobject'. thus we need to pull the module directly out of # sys.modules @@ -2134,15 +2135,11 @@ def redoModule(name, out_name, mod_file_name, doing_builtins, imported_module_na report("Failed to find CLR module " + name) break if mod: - action("opening %r", out_name) - outfile = fopen(out_name, "w") action("restoring") r = ModuleRedeclarator(mod, outfile, mod_file_name, doing_builtins=doing_builtins) r.redo(name, imported_module_names) action("flushing") r.flush() - action("closing %r", out_name) - outfile.close() else: report("Failed to find imported module in sys.modules") @@ -2283,57 +2280,72 @@ def processOne(name, mod_file_name, doing_builtins): sys.stdout.flush() action("doing nothing") #noinspection PyBroadException + outfile = None try: - fname = buildOutputName(subdir, name) - - old_modules = list(sys.modules.keys()) - imported_module_names = [] - class MyFinder: - def find_module(self, fullname, path=None): - if fullname != name: - imported_module_names.append(fullname) - return None - - my_finder = None - if hasattr(sys, 'meta_path'): - my_finder = MyFinder() - sys.meta_path.append(my_finder) - else: - imported_module_names = None - - action("importing %r", name) try: + fname = buildOutputName(subdir, name) + action("opening %r", fname) + outfile = fopen(fname, "w") + old_modules = list(sys.modules.keys()) + imported_module_names = [] + class MyFinder: + def find_module(self, fullname, path=None): + if fullname != name: + imported_module_names.append(fullname) + return None + + my_finder = None + if hasattr(sys, 'meta_path'): + my_finder = MyFinder() + sys.meta_path.append(my_finder) + else: + imported_module_names = None + + action("importing") __import__(name) # sys.modules will fill up with what we want - except ImportError: + + if my_finder: + sys.meta_path.remove(my_finder) + if imported_module_names is None: + imported_module_names = [m for m in sys.modules.keys() if m not in old_modules] + + redoModule(name, outfile, mod_file_name, doing_builtins, imported_module_names) + # The C library may have called Py_InitModule() multiple times to define several modules (gtk._gtk and gtk.gdk); + # restore all of them + if imported_module_names: + for m in sys.modules.keys(): + action("looking at possible submodule %r", m) + # if module has __file__ defined, it has Python source code and doesn't need a skeleton + if m not in old_modules and m not in imported_module_names and m != name and not hasattr(sys.modules[m], '__file__'): + if not quiet: + say(m) + sys.stdout.flush() + fname = buildOutputName(subdir, m) + action("opening %r", fname) + subfile = fopen(fname, "w") + try: + redoModule(m, subfile, mod_file_name, doing_builtins, imported_module_names) + finally: + action("closing %r", fname) + subfile.close() + except: exctype, value = sys.exc_info()[:2] - report("Name %r failed to import: %r", name, str(value)) + msg = "Failed to process %r while %s: %s" % (name, _current_action, str(value)) + report(msg) + if outfile is not None and not outfile.closed: + outfile.write("# encoding: %s\n" % OUT_ENCODING) + outfile.write("# module %s\n" % name) + outfile.write(VERSION_CONTROL_HEADER_FORMAT % (mod_file_name, VERSION)) + outfile.write("\n\n") + outfile.write("# Skeleton generation error:\n#\n# " + msg + "\n") + if debug_mode: + if sys.platform == 'cli': + traceback.print_exc(file=sys.stderr) + raise return False - - if my_finder: - sys.meta_path.remove(my_finder) - if imported_module_names is None: - imported_module_names = [m for m in sys.modules.keys() if m not in old_modules] - - redoModule(name, fname, mod_file_name, doing_builtins, imported_module_names) - # The C library may have called Py_InitModule() multiple times to define several modules (gtk._gtk and gtk.gdk); - # restore all of them - if imported_module_names: - for m in sys.modules.keys(): - action("looking at possible submodule %r", m) - # if module has __file__ defined, it has Python source code and doesn't need a skeleton - if m not in old_modules and m not in imported_module_names and m != name and not hasattr(sys.modules[m], '__file__'): - if not quiet: - say(m) - sys.stdout.flush() - fname = buildOutputName(subdir, m) - redoModule(m, fname, mod_file_name, doing_builtins, imported_module_names) - except: - report("Failed to process %r while %s", name, _current_action) - if debug_mode: - if sys.platform == 'cli': - traceback.print_exc(file=sys.stderr) - raise - return False + finally: + if outfile is not None and not outfile.closed: + outfile.close() return True if __name__ == "__main__": @@ -2434,7 +2446,7 @@ if __name__ == "__main__": names.remove('__main__') # we don't want ourselves processed ok = True for name in names: - ok = ok and processOne(name, None, True) + ok = processOne(name, None, True) and ok if not ok: sys.exit(1) diff --git a/python/helpers/pydev/pydev_ipython_console.py b/python/helpers/pydev/pydev_ipython_console.py index 7bb0049ad3de..fb835ce61709 100644 --- a/python/helpers/pydev/pydev_ipython_console.py +++ b/python/helpers/pydev/pydev_ipython_console.py @@ -15,14 +15,13 @@ try: from pydev_ipython_console_010 import PyDevFrontEnd sys.stderr.write('PyDev console: using IPython 0.10\n') -except ImportError: +except : #IPython 0.11 broke compatibility... from pydev_ipython_console_011 import PyDevFrontEnd sys.stderr.write('PyDev console: using IPython 0.11\n') - #======================================================================================================================= # InterpreterInterface #======================================================================================================================= diff --git a/python/helpers/pydev/pydev_log.py b/python/helpers/pydev/pydev_log.py new file mode 100644 index 000000000000..2e66f3342717 --- /dev/null +++ b/python/helpers/pydev/pydev_log.py @@ -0,0 +1,30 @@ +import logging +import os +import sys +from pydevd_constants import DebugInfoHolder + +logger = logging.getLogger('pydev') +#hdlr = logging.FileHandler('/var/tmp/pycharm-debug-%d.log'%os.getpid()) +#formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') +#hdlr.setFormatter(formatter) +#logger.addHandler(hdlr) +logger.setLevel(logging.DEBUG) + +def debug(message): + logger.debug(message) + if DebugInfoHolder.DEBUG_TRACE_LEVEL>2: + sys.stderr.write(message) + +def warn(message): + logger.warn(message) + if DebugInfoHolder.DEBUG_TRACE_LEVEL>1: + sys.stderr.write(message) + +def info(message): + logger.info(message) + sys.stderr.write(message) + +def error(message): + logger.error(message) + sys.stderr.write(message) + diff --git a/python/helpers/pydev/pydev_monkey.py b/python/helpers/pydev/pydev_monkey.py index 391b6aae4b83..bd2f23f479b5 100644 --- a/python/helpers/pydev/pydev_monkey.py +++ b/python/helpers/pydev/pydev_monkey.py @@ -46,9 +46,10 @@ def patch_args(args): return new_args def monkey_patch_os(funcname, create_func): - original_name = 'original_' + funcname - setattr(os, original_name, getattr(os, funcname)) - setattr(os, funcname, create_func(original_name)) + if hasattr(os, funcname): + original_name = 'original_' + funcname + setattr(os, original_name, getattr(os, funcname)) + setattr(os, funcname, create_func(original_name)) def create_execl(original_name): def new_execl(path, *args): diff --git a/python/helpers/pydev/pydevd.py b/python/helpers/pydev/pydevd.py index bfde4b94e951..2d5fe30fe309 100644 --- a/python/helpers/pydev/pydevd.py +++ b/python/helpers/pydev/pydevd.py @@ -63,6 +63,7 @@ import traceback import pydevd_vm_type import pydevd_tracing import pydevd_io +import pydev_log from pydevd_additional_thread_info import PyDBAdditionalThreadInfo import time import os @@ -623,12 +624,12 @@ class PyDB: except: pass - if DEBUG_TRACE_BREAKPOINTS > 0: + if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: sys.stderr.write('Removed breakpoint:%s\n' % (file,)) sys.stderr.flush() except KeyError: #ok, it's not there... - if DEBUG_TRACE_BREAKPOINTS > 0: + if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: #Sometimes, when adding a breakpoint, it adds a remove command before (don't really know why) sys.stderr.write("breakpoint not found: %s - %s\n" % (file, line)) sys.stderr.flush() @@ -660,10 +661,13 @@ class PyDB: if is_notify_on_terminate: update_exception_hook(self) + if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: + pydev_log.error("Exceptions to hook on terminate: %s\n" % (self.always_exception_set,)) + if is_notify_always: self.always_exception_set.add(exception) - if DEBUG_TRACE_BREAKPOINTS > 0: - sys.stderr.write("Exceptions to hook : %s\n" % (self.always_exception_set,)) + if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: + pydev_log.error("Exceptions to hook always: %s\n" % (self.always_exception_set,)) self.setTracingForUntracedContexts() elif cmd_id == CMD_REMOVE_EXCEPTION_BREAK: @@ -1023,43 +1027,48 @@ class PyDB: def processCommandLine(argv): """ parses the arguments. removes our arguments from the command line """ - retVal = {} - retVal['client'] = '' - retVal['server'] = False - retVal['port'] = 0 - retVal['file'] = '' - retVal['multiproc'] = False + setup = {} + setup['client'] = '' + setup['server'] = False + setup['port'] = 0 + setup['file'] = '' + setup['multiproc'] = False i = 0 del argv[0] while (i < len(argv)): if (argv[i] == '--port'): del argv[i] - retVal['port'] = int(argv[i]) + setup['port'] = int(argv[i]) del argv[i] elif (argv[i] == '--vm_type'): del argv[i] - retVal['vm_type'] = argv[i] + setup['vm_type'] = argv[i] del argv[i] elif (argv[i] == '--client'): del argv[i] - retVal['client'] = argv[i] + setup['client'] = argv[i] del argv[i] elif (argv[i] == '--server'): del argv[i] - retVal['server'] = True + setup['server'] = True elif (argv[i] == '--file'): del argv[i] - retVal['file'] = argv[i] + setup['file'] = argv[i] i = len(argv) # pop out, file is our last argument elif (argv[i] == '--DEBUG_RECORD_SOCKET_READS'): del argv[i] - retVal['DEBUG_RECORD_SOCKET_READS'] = True + setup['DEBUG_RECORD_SOCKET_READS'] = True + elif (argv[i] == '--DEBUG'): + del argv[i] + setup['DEBUG_RECORD_SOCKET_READS'] = True + setup['DEBUG_TRACE_BREAKPOINTS'] = 1 + setup['DEBUG_TRACE_LEVEL'] = 3 elif (argv[i] == '--multiproc'): del argv[i] - retVal['multiproc'] = True + setup['multiproc'] = True else: raise ValueError("unexpected option " + argv[i]) - return retVal + return setup def usage(doExit=0): sys.stdout.write('Usage:\n') @@ -1262,26 +1271,36 @@ if __name__ == '__main__': sys.modules['psyco'] = pydevd_psyco_stub - PydevdLog(2, "Executing file ", setup['file']) - PydevdLog(2, "arguments:", str(sys.argv)) + pydev_log.debug("Executing file %s" % setup['file']) + pydev_log.debug("arguments: %s"% str(sys.argv)) + + pydevd_vm_type.SetupType(setup.get('vm_type', None)) DebugInfoHolder.DEBUG_RECORD_SOCKET_READS = setup.get('DEBUG_RECORD_SOCKET_READS', False) + DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS = setup.get('', -1) + DebugInfoHolder.DEBUG_TRACE_LEVEL = setup.get('DEBUG_TRACE_LEVEL', -1) port = setup['port'] if setup['multiproc']: + pydev_log.debug("Started in multiproc mode") dispatcher = Dispatcher() dispatcher.connect(setup) if dispatcher.port is not None: port = dispatcher.port - sys.stderr.write("pydev debugger: process %d is connecting\n"% os.getpid()) + pydev_log.debug("Received port %d" %port) + pydev_log.info("pydev debugger: process %d is connecting\n"% os.getpid()) + import pydev_monkey - pydev_monkey.patch_new_process_functions() + try: + pydev_monkey.patch_new_process_functions() + except: + logger.error("Error patching process functions") else: - sys.stderr.write("pydev debugger: couldn't get port for new debug process\n") + pydev_log.error("pydev debugger: couldn't get port for new debug process\n") else: - sys.stderr.write("pydev debugger: starting\n") + pydev_log.info("pydev debugger: starting\n") debugger = PyDB() debugger.connect(setup['client'], port) diff --git a/python/helpers/pydev/pydevd_breakpoints.py b/python/helpers/pydev/pydevd_breakpoints.py index 626b86e87bd6..22fbbc17006f 100644 --- a/python/helpers/pydev/pydevd_breakpoints.py +++ b/python/helpers/pydev/pydevd_breakpoints.py @@ -1,5 +1,6 @@ from pydevd_constants import * import sys +import pydev_log _original_excepthook = None _handle_exceptions = None @@ -44,8 +45,8 @@ class LineBreakpoint: return breakDict def trace(self, file, line, func_name): - if DEBUG_TRACE_BREAKPOINTS > 0: - sys.stderr.write('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name)) + if DebugInfoHolder.DEBUG_TRACE_BREAKPOINTS > 0: + pydev_log.debug('Added breakpoint:%s - line:%s - func_name:%s\n' % (file, line, func_name)) sys.stderr.flush() def add(self, breakpoints, file, line, func_name): diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index c1311a6dc094..290e02f41831 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -166,7 +166,7 @@ def PydevdLog(level, *args): 1 warnings/significant events 2 informational trace """ - if level <= DEBUG_TRACE_LEVEL: + if level <= DebugInfoHolder.DEBUG_TRACE_LEVEL: #yes, we can have errors printing if the console of the program has been finished (and we're still trying to print something) try: sys.stderr.write('%s\n' % (args,)) @@ -325,7 +325,7 @@ class WriterThread(PyDBDaemonThread): #but the thread was still not liberated return out = cmd.getOutgoing() - if DEBUG_TRACE_LEVEL >= 1: + if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1: out_message = 'sending cmd: ' out_message += ID_TO_MEANING.get(out[:3], 'UNKNOWN') out_message += ' ' @@ -343,7 +343,7 @@ class WriterThread(PyDBDaemonThread): time.sleep(self.timeout) except Exception: GlobalDebuggerHolder.globalDbg.FinishDebuggingSession() - if DEBUG_TRACE_LEVEL >= 0: + if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 0: traceback.print_exc() @@ -434,7 +434,7 @@ class NetCommandFactory: def makeErrorMessage(self, seq, text): cmd = NetCommand(CMD_ERROR, seq, text) - if DEBUG_TRACE_LEVEL > 2: + if DebugInfoHolder.DEBUG_TRACE_LEVEL > 2: sys.stderr.write("Error: %s" % (text,)) return cmd diff --git a/python/helpers/pydev/pydevd_constants.py b/python/helpers/pydev/pydevd_constants.py index b59f433df55b..d715fba5a89b 100644 --- a/python/helpers/pydev/pydevd_constants.py +++ b/python/helpers/pydev/pydevd_constants.py @@ -16,13 +16,14 @@ except: setattr(__builtin__, 'True', 1) setattr(__builtin__, 'False', 0) -DEBUG_TRACE_LEVEL = -1 -DEBUG_TRACE_BREAKPOINTS = -1 + class DebugInfoHolder: #we have to put it here because it can be set through the command line (so, the #already imported references would not have it). DEBUG_RECORD_SOCKET_READS = False + DEBUG_TRACE_LEVEL = -1 + DEBUG_TRACE_BREAKPOINTS = -1 #Optimize with psyco? This gave a 50% speedup in the debugger in tests USE_PSYCO_OPTIMIZATION = True diff --git a/python/helpers/pydev/pydevd_frame.py b/python/helpers/pydev/pydevd_frame.py index e39d7283bf97..bfd2f44f86ca 100644 --- a/python/helpers/pydev/pydevd_frame.py +++ b/python/helpers/pydev/pydevd_frame.py @@ -8,6 +8,7 @@ from pydevd_breakpoints import * #@UnusedWildImport import traceback #@Reimport import os.path import sys +import pydev_log basename = os.path.basename @@ -166,8 +167,8 @@ class PyDBFrame: return self.trace_dispatch except: - sys.stderr.write('Error while evaluating condition \'%s\': %s\n' % (breakpoint.condition, sys.exc_info()[1])) - sys.stderr.flush() + pydev_log.info('Error while evaluating condition \'%s\': %s\n' % (breakpoint.condition, sys.exc_info()[1])) + return self.trace_dispatch if breakpoint.expression is not None: @@ -332,8 +333,7 @@ class PyDBFrame: if not val: flag = False except: - sys.stderr.write('Error while evaluating condition \'%s\': %s\n' % (django_breakpoint.condition, sys.exc_info()[1])) - sys.stderr.flush() + pydev_log.info('Error while evaluating condition \'%s\': %s\n' % (django_breakpoint.condition, sys.exc_info()[1])) if django_breakpoint.expression is not None: try: diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py index eede24de8cc9..5b380f58d339 100644 --- a/python/helpers/pydev/pydevd_vars.py +++ b/python/helpers/pydev/pydevd_vars.py @@ -8,6 +8,7 @@ from types import * #@UnusedWildImport from code import compile_command from code import InteractiveInterpreter import pydevconsole +import pydev_log try: from StringIO import StringIO @@ -244,8 +245,8 @@ def frameVarsToXML(frame): xml += varToXML(v, str(k)) except Exception: traceback.print_exc() - sys.stderr.write("Unexpected error, recovered safely.\n") - sys.stderr.flush() + pydev_log.error("Unexpected error, recovered safely.\n") + return xml def iterFrames(initialFrame): diff --git a/python/pydevSrc/com/jetbrains/python/debugger/PySourcePosition.java b/python/pydevSrc/com/jetbrains/python/debugger/PySourcePosition.java index 808c739ae5a2..8bc97d22634e 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/PySourcePosition.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/PySourcePosition.java @@ -1,6 +1,8 @@ package com.jetbrains.python.debugger; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.Nullable; public abstract class PySourcePosition { @@ -8,10 +10,22 @@ public abstract class PySourcePosition { private final int line; protected PySourcePosition(final String file, final int line) { - this.file = FileUtil.toSystemIndependentName(file); + this.file = normalize(file); this.line = line; } + @Nullable + private static String normalize(@Nullable String file) { + if (file == null) { + return file; + } + String res = FileUtil.toSystemIndependentName(file); + if (SystemInfo.isWindows) { + res = res.toLowerCase(); + } + return res; + } + public String getFile() { return file; } diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index 338a400c790a..5a439e52cb8c 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -586,7 +586,7 @@ - diff --git a/python/src/com/jetbrains/python/actions/CreatePackageAction.java b/python/src/com/jetbrains/python/actions/CreatePackageAction.java index 125bcde05362..1474750b3a1c 100644 --- a/python/src/com/jetbrains/python/actions/CreatePackageAction.java +++ b/python/src/com/jetbrains/python/actions/CreatePackageAction.java @@ -48,7 +48,7 @@ public class CreatePackageAction extends DumbAwareAction { } } - private static void createInitPyInHierarchy(PsiDirectory created, PsiDirectory ancestor) { + public static void createInitPyInHierarchy(PsiDirectory created, PsiDirectory ancestor) { do { createInitPy(created); created = created.getParent(); @@ -58,6 +58,9 @@ public class CreatePackageAction extends DumbAwareAction { private static void createInitPy(PsiDirectory directory) { final FileTemplateManager fileTemplateManager = FileTemplateManager.getInstance(); final FileTemplate template = fileTemplateManager.getInternalTemplate("Python Script"); + if (directory.findFile(PyNames.INIT_DOT_PY) != null) { + return; + } if (template != null) { try { FileTemplateUtil.createFromTemplate(template, PyNames.INIT_DOT_PY, fileTemplateManager.getDefaultProperties(), directory); diff --git a/python/src/com/jetbrains/python/codeInsight/codeFragment/PyCodeFragmentUtil.java b/python/src/com/jetbrains/python/codeInsight/codeFragment/PyCodeFragmentUtil.java index c58cade63a2b..0d3be71ba1dc 100644 --- a/python/src/com/jetbrains/python/codeInsight/codeFragment/PyCodeFragmentUtil.java +++ b/python/src/com/jetbrains/python/codeInsight/codeFragment/PyCodeFragmentUtil.java @@ -11,6 +11,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.HashSet; import com.jetbrains.python.PyBundle; import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache; +import com.jetbrains.python.codeInsight.controlflow.ReadWriteInstruction; import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyBinaryExpressionNavigator; @@ -76,6 +77,9 @@ public class PyCodeFragmentUtil { if (next instanceof ConditionalInstruction){ continue; } + if (next instanceof ReadWriteInstruction && ((ReadWriteInstruction)next).getAccess().isAssertTypeAccess()) { + continue; + } final PsiElement nextElement = next.getElement(); // Ignore binary operations control flow if (nextElement != null && PyBinaryExpressionNavigator.getBinaryExpressionByOperand(nextElement) != null){ diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index 431b8b369bdc..384925c8a8a7 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -29,7 +29,7 @@ public class PyNamedTupleType extends PyClassType implements PyCallableType { private final boolean myDefinition; private final PsiElement myDeclaration; private final List myFields; - + private static final ImmutableSet ourClassMembers = ImmutableSet.of("_fields", "_make"); private static final ImmutableSet ourInstanceMembers = ImmutableSet.of("_asdict", "_replace"); @@ -83,7 +83,7 @@ public class PyNamedTupleType extends PyClassType implements PyCallableType { @Override public String getName() { - return "namedtuple '" + myName + "'"; + return myName; } @Override @@ -99,6 +99,16 @@ public class PyNamedTupleType extends PyClassType implements PyCallableType { return null; } + @Override + public PyClassType toInstance() { + return myIsDefinition ? new PyNamedTupleType(myDeclaration, myName, myFields, false) : this; + } + + @Override + public String toString() { + return "PyNamedTupleType: " + myName; + } + @Nullable public static PyType fromCall(PyCallExpression call) { final String name = PyUtil.strValue(call.getArgument(0, PyExpression.class)); diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes2.properties b/python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes2.properties index f44c59b3c64b..e83613538001 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes2.properties +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/StdlibTypes2.properties @@ -128,7 +128,7 @@ __builtin__.int.__sub__ = \ :rtype: int \n\ __builtin__.int.__mul__ = \ - :type y: int or long or float or complex or string or list \n\ + :type y: int or long or float or complex \n\ :rtype: int \n\ __builtin__.int.__floordiv__ = \ @@ -631,7 +631,7 @@ __builtin__.str.encode = \ :rtype: bytes \n\ __builtin__.str.endswith = \ - :type suffix: string \n\ + :type suffix: string or tuple \n\ :type start: int or long or None \n\ :type end: int or long or None \n\ :rtype: bool \n\ @@ -730,7 +730,7 @@ __builtin__.str.splitlines = \ :rtype: list of bytes \n\ __builtin__.str.startswith = \ - :type prefix: string \n\ + :type prefix: string or tuple \n\ :type start: int or long or None \n\ :type end: int or long or None \n\ :rtype: bool \n\ @@ -805,7 +805,7 @@ __builtin__.unicode.encode = \ :rtype: bytes \n\ __builtin__.unicode.endswith = \ - :type suffix: string \n\ + :type suffix: string or tuple \n\ :type start: int or long or None \n\ :type end: int or long or None \n\ :rtype: bool \n\ @@ -910,7 +910,7 @@ __builtin__.unicode.splitlines = \ :rtype: list of unicode \n\ __builtin__.unicode.startswith = \ - :type prefix: string \n\ + :type prefix: string or tuple \n\ :type start: int or long or None \n\ :type end: int or long or None \n\ :rtype: bool \n\ @@ -1108,6 +1108,82 @@ __builtin__.file.writelines = \ :type sequence_of_strings: collections.Iterable of string \n\ +## 9.4. decimal + +decimal.Decimal.as_tuple = \ + :rtype: decimal.DecimalTuple \n\ + +decimal.Decimal.__add__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__sub__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__mul__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__floordiv__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__mod__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__pow__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__div__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__truediv__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__radd__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__rsub__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__rmul__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__rfloordiv__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__rmod__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__rpow__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__rdiv__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__rtruediv__ = \ + :type other: decimal.Decimal or int or long or float or complex \n\ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__pos__ = \ + :rtype: decimal.Decimal \n\ + +decimal.Decimal.__neg__ = \ + :rtype: decimal.Decimal \n\ + + ## 18.2. json json.loads = \ diff --git a/python/src/com/jetbrains/python/console/ConsoleVisitorFilter.java b/python/src/com/jetbrains/python/console/ConsoleVisitorFilter.java index d54f2011b64a..5ad0850800ae 100644 --- a/python/src/com/jetbrains/python/console/ConsoleVisitorFilter.java +++ b/python/src/com/jetbrains/python/console/ConsoleVisitorFilter.java @@ -1,6 +1,8 @@ package com.jetbrains.python.console; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.jetbrains.python.console.completion.PydevConsoleElement; import com.jetbrains.python.inspections.*; import com.jetbrains.python.validation.DocStringAnnotator; import org.jetbrains.annotations.NotNull; @@ -12,9 +14,9 @@ import org.jetbrains.annotations.NotNull; */ public class ConsoleVisitorFilter implements PythonVisitorFilter { @Override - public boolean isSupported(@NotNull Class visitorClass, @NotNull PsiElement element) { + public boolean isSupported(@NotNull Class visitorClass, @NotNull PsiElement element, PsiFile containingFile) { //if we're in console - if (PydevConsoleRunner.isInPydevConsole(element)) { + if (element instanceof PydevConsoleElement || containingFile.getCopyableUserData(PydevConsoleRunner.CONSOLE_KEY) != null) { //inspections if (visitorClass == PyUnusedLocalInspectionVisitor.class || visitorClass == PyUnboundLocalVariableInspection.Visitor.class || visitorClass == PyStatementEffectInspection.class || visitorClass == PySingleQuotedDocstringInspection.class || diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index 1a7ac4d2be55..af8984e5464c 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -476,8 +476,15 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr XBreakpoint breakpoint = null; if (threadInfo.isStopOnBreakpoint()) { final PySourcePosition position = frames.get(0).getPosition(); + breakpoint = myRegisteredBreakpoints.get(position); if (breakpoint == null) { + System.out.println("Stopped:" + position.getFile() + ", " + position.getLine()); + System.out.println("Registered:"); + for (PySourcePosition s: myRegisteredBreakpoints.keySet()) { + System.out.println(s.getFile() + ", " + s.getLine()); + } + myDebugger.removeTempBreakpoint(position.getFile(), position.getLine()); } } diff --git a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java index e2c7c326f935..816e71120b66 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugRunner.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugRunner.java @@ -165,7 +165,7 @@ public class PyDebugRunner extends GenericProgramRunner { } if (ApplicationManager.getApplication().isUnitTestMode()) { - debugParams.addParameter("--DEBUG_RECORD_SOCKET_READS"); + debugParams.addParameter("--DEBUG"); } final String[] debuggerArgs = new String[]{ diff --git a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java index d65905543dc3..78758da2a1a5 100644 --- a/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTypeCheckerInspection.java @@ -4,13 +4,10 @@ import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiElementVisitor; -import com.intellij.psi.PsiReference; +import com.intellij.psi.*; import com.jetbrains.python.PyNames; import com.jetbrains.python.documentation.PythonDocumentationProvider; import com.jetbrains.python.psi.*; -import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.types.*; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; @@ -53,21 +50,34 @@ public class PyTypeCheckerInspection extends PyInspection { } final PyType argType = entry.getKey().getType(myTypeEvalContext); final PyType paramType = p.getType(myTypeEvalContext); - checkTypes(paramType, argType, entry.getKey(), myTypeEvalContext); + checkTypes(paramType, argType, entry.getKey(), myTypeEvalContext, true); } } } @Override public void visitPyBinaryExpression(PyBinaryExpression node) { - // TODO: Support operators besides PyBinaryExpression - final PsiReference ref = node.getReference(PyResolveContext.noImplicits().withTypeEvalContext(myTypeEvalContext)); + final PsiPolyVariantReference ref = node.getReference(resolveWithoutImplicits()); if (ref != null) { - final PsiElement resolved = ref.resolve(); - if (resolved instanceof PyFunction) { - final PyFunction fun = (PyFunction)resolved; - final PyExpression arg = PyNames.isRightOperatorName(fun.getName()) ? node.getLeftExpression() : node.getRightExpression(); - checkSingleArgumentFunction(fun, arg); + final ResolveResult[] results = ref.multiResolve(false); + String error = null; + PyExpression arg = null; + for (ResolveResult result : results) { + final PsiElement resolved = result.getElement(); + if (resolved instanceof PyFunction) { + final PyFunction fun = (PyFunction)resolved; + arg = PyNames.isRightOperatorName(fun.getName()) ? node.getLeftExpression() : node.getRightExpression(); + error = checkSingleArgumentFunction(fun, arg, false); + if (error == null) { + return; + } + } + else { + return; + } + } + if (error != null) { + registerProblem(arg, error); } } } @@ -75,16 +85,17 @@ public class PyTypeCheckerInspection extends PyInspection { @Override public void visitPySubscriptionExpression(PySubscriptionExpression node) { // TODO: Support slice PySliceExpressions - final PsiReference ref = node.getReference(PyResolveContext.noImplicits().withTypeEvalContext(myTypeEvalContext)); + final PsiReference ref = node.getReference(resolveWithoutImplicits()); if (ref != null) { final PsiElement resolved = ref.resolve(); if (resolved instanceof PyFunction) { - checkSingleArgumentFunction((PyFunction)resolved, node.getIndexExpression()); + checkSingleArgumentFunction((PyFunction)resolved, node.getIndexExpression(), true); } } } - private void checkSingleArgumentFunction(@NotNull PyFunction fun, @Nullable PyExpression argument) { + @Nullable + private String checkSingleArgumentFunction(@NotNull PyFunction fun, @Nullable PyExpression argument, boolean registerProblem) { if (argument != null) { final PyParameter[] parameters = fun.getParameterList().getParameters(); if (parameters.length == 2) { @@ -92,22 +103,29 @@ public class PyTypeCheckerInspection extends PyInspection { if (p != null) { final PyType argType = argument.getType(myTypeEvalContext); final PyType paramType = p.getType(myTypeEvalContext); - checkTypes(paramType, argType, argument, myTypeEvalContext); + return checkTypes(paramType, argType, argument, myTypeEvalContext, registerProblem); } } } + return null; } - private void checkTypes(PyType superType, PyType subType, PsiElement node, TypeEvalContext context) { + @Nullable + private String checkTypes(PyType superType, PyType subType, PsiElement node, TypeEvalContext context, boolean registerPoblem) { if (subType != null && superType != null) { if (!PyTypeChecker.match(superType, subType, context)) { - registerProblem(node, String.format("Expected type '%s', got '%s' instead", - PythonDocumentationProvider.getTypeName(superType, context), - PythonDocumentationProvider.getTypeName(subType, myTypeEvalContext))); + final String msg = String.format("Expected type '%s', got '%s' instead", + PythonDocumentationProvider.getTypeName(superType, context), + PythonDocumentationProvider.getTypeName(subType, myTypeEvalContext)); + if (registerPoblem) { + registerProblem(node, msg); + } + return msg; } } + return null; } - }; + } @Override public void inspectionFinished(LocalInspectionToolSession session, ProblemsHolder problemsHolder) { diff --git a/python/src/com/jetbrains/python/inspections/PythonVisitorFilter.java b/python/src/com/jetbrains/python/inspections/PythonVisitorFilter.java index 88665715bb1c..2d8fea63f09b 100644 --- a/python/src/com/jetbrains/python/inspections/PythonVisitorFilter.java +++ b/python/src/com/jetbrains/python/inspections/PythonVisitorFilter.java @@ -2,6 +2,7 @@ package com.jetbrains.python.inspections; import com.intellij.lang.LanguageExtension; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; /** @@ -11,8 +12,7 @@ import org.jetbrains.annotations.NotNull; * check if we should visit element */ public interface PythonVisitorFilter { - public static final LanguageExtension INSTANCE = - new LanguageExtension("Pythonid.visitorFilter"); + LanguageExtension INSTANCE = new LanguageExtension("Pythonid.visitorFilter"); - boolean isSupported(@NotNull Class visitorClass, @NotNull PsiElement element); + boolean isSupported(@NotNull Class visitorClass, @NotNull PsiElement element, PsiFile containingFile); } diff --git a/python/src/com/jetbrains/python/psi/PyUtil.java b/python/src/com/jetbrains/python/psi/PyUtil.java index 07fc238e551e..7d04e8161f13 100644 --- a/python/src/com/jetbrains/python/psi/PyUtil.java +++ b/python/src/com/jetbrains/python/psi/PyUtil.java @@ -10,6 +10,7 @@ import com.intellij.ide.fileTemplates.FileTemplateManager; import com.intellij.lang.ASTNode; import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtil; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.ui.MessageType; @@ -498,7 +499,7 @@ public class PyUtil { return false; } return PsiTreeUtil.isAncestor(statement.getLeftHandSideExpression(), element, false); - } + } public static boolean isDocString(PyExpression expression) { final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(expression, PyDocStringOwner.class); @@ -783,22 +784,32 @@ public class PyUtil { return selfName; } - @Nullable - public static VirtualFile findInRoots(Module module, String path) { - final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - VirtualFile result = findInRoots(moduleRootManager.getContentRoots(), path); - if (result == null) { - result = findInRoots(moduleRootManager.getSourceRoots(), path); + @NotNull + public static List getSourceRoots(@NotNull PsiElement foothold) { + final Module module = ModuleUtil.findModuleForPsiElement(foothold); + if (module != null) { + return getSourceRoots(module); } + return Collections.emptyList(); + } + + @NotNull + public static List getSourceRoots(@NotNull Module module) { + final List result = new ArrayList(); + final ModuleRootManager manager = ModuleRootManager.getInstance(module); + result.addAll(Arrays.asList(manager.getSourceRoots())); + result.addAll(Arrays.asList(manager.getContentRoots())); return result; } @Nullable - public static VirtualFile findInRoots(VirtualFile[] roots, String path) { - for (VirtualFile root : roots) { - VirtualFile settingsFile = root.findFileByRelativePath(path); - if (settingsFile != null) { - return settingsFile; + public static VirtualFile findInRoots(Module module, String path) { + if (module != null) { + for (VirtualFile root : getSourceRoots(module)) { + VirtualFile file = root.findFileByRelativePath(path); + if (file != null) { + return file; + } } } return null; diff --git a/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java index 6ba49a70928c..8b6efcfde24c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyBaseElementImpl.java @@ -12,7 +12,6 @@ import com.intellij.psi.templateLanguages.OuterLanguageElement; import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider; import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.TokenSet; -import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PythonFileType; import com.jetbrains.python.PythonLanguage; import com.jetbrains.python.inspections.PythonVisitorFilter; @@ -73,7 +72,7 @@ public class PyBaseElementImpl extends StubBasedPsiElemen } public static boolean isAcceptedFor(@NotNull final PsiElement element, @NotNull Class clazz) { - PsiFile file = PsiTreeUtil.getNonStrictParentOfType(element, PsiFile.class); + PsiFile file = element.getContainingFile(); if (file != null) { Language lang = file.getLanguage(); FileViewProvider vProvider = file.getViewProvider(); @@ -81,7 +80,7 @@ public class PyBaseElementImpl extends StubBasedPsiElemen lang = vProvider.getBaseLanguage(); } PythonVisitorFilter filter = PythonVisitorFilter.INSTANCE.forLanguage(lang); - return filter != null ? filter.isSupported(clazz, element) : true; + return filter != null ? filter.isSupported(clazz, element, file) : true; } return true; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index d6f0f69b750e..b1483b725804 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -18,6 +18,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.*; import com.intellij.util.*; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.SoftHashMap; import com.jetbrains.python.PyElementTypes; import com.jetbrains.python.PyNames; import com.jetbrains.python.PyTokenTypes; @@ -56,6 +57,8 @@ public class PyClassImpl extends PyPresentableElementImpl implement return CachedValuesManager.getManager(getProject()).createCachedValue(new NewStyleCachedValueProvider(), false); } }; + + private final SoftHashMap myPropertyCache = new SoftHashMap(); @Override public PyType getType(@NotNull TypeEvalContext context) { @@ -604,7 +607,16 @@ public class PyClassImpl extends PyPresentableElementImpl implement @Nullable @Override public Property findProperty(@NotNull final String name) { - return scanProperties(name, null, true); + synchronized (myPropertyCache) { + if (myPropertyCache.containsKey(name)) { + return myPropertyCache.get(name); + } + } + final Property result = scanProperties(name, null, true); + synchronized (myPropertyCache) { + myPropertyCache.put(name, result); + } + return result; } @Nullable @@ -1025,6 +1037,9 @@ public class PyClassImpl extends PyPresentableElementImpl implement if (myInstanceAttributes != null) { myInstanceAttributes = null; } + synchronized (myPropertyCache) { + myPropertyCache.clear(); + } } @NotNull diff --git a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java index 082ec398f2c7..d5be4db61fac 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyImportElementImpl.java @@ -43,7 +43,8 @@ public class PyImportElementImpl extends PyBaseElementImpl @Nullable public PyReferenceExpression getImportReference() { - return findChildByClass(PyReferenceExpression.class); + final ASTNode node = getNode().findChildByType(PyElementTypes.REFERENCE_EXPRESSION); + return node == null ? null : (PyReferenceExpression) node.getPsi(); } public PyQualifiedName getImportedQName() { diff --git a/python/src/com/jetbrains/python/psi/impl/PyOperatorReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/PyOperatorReferenceImpl.java index e729232123f4..6b738ae75761 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyOperatorReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyOperatorReferenceImpl.java @@ -39,20 +39,18 @@ public class PyOperatorReferenceImpl extends PyReferenceImpl { typeEvalContext.trace("Trying to resolve left operator"); typeEvalContext.traceIndent(); try { - res = resolveMember(expr.getLeftExpression(), name); + res.addAll(resolveMember(expr.getLeftExpression(), name)); } finally { typeEvalContext.traceUnindent(); } - if (res.isEmpty()) { - typeEvalContext.trace("Trying to resolve right operator"); - typeEvalContext.traceIndent(); - try { - res = resolveMember(expr.getRightExpression(), leftToRightOperatorName(name)); - } - finally { - typeEvalContext.traceUnindent(); - } + typeEvalContext.trace("Trying to resolve right operator"); + typeEvalContext.traceIndent(); + try { + res.addAll(resolveMember(expr.getRightExpression(), leftToRightOperatorName(name))); + } + finally { + typeEvalContext.traceUnindent(); } } } diff --git a/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodHandler.java b/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodHandler.java index 0d39ea8356fe..d1d758503719 100644 --- a/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodHandler.java +++ b/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodHandler.java @@ -25,7 +25,7 @@ import org.jetbrains.annotations.Nullable; * @author oleg */ public class PyExtractMethodHandler implements RefactoringActionHandler { - + @Override public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, final DataContext dataContext) { editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE); // select editor text fragment @@ -35,12 +35,11 @@ public class PyExtractMethodHandler implements RefactoringActionHandler { invokeOnEditor(project, editor, file); } - + @Override public void invoke(@NotNull final Project project, @NotNull final PsiElement[] elements, final DataContext dataContext) { - // ignore this } - private void invokeOnEditor(final Project project, final Editor editor, final PsiFile file) { + private static void invokeOnEditor(final Project project, final Editor editor, final PsiFile file) { CommonRefactoringUtil.checkReadOnlyStatus(project, file); PsiElement element1 = null; PsiElement element2 = null; @@ -112,7 +111,7 @@ public class PyExtractMethodHandler implements RefactoringActionHandler { } @Nullable - private PsiElement[] getStatementsRange(final PsiElement element1, final PsiElement element2) { + private static PsiElement[] getStatementsRange(final PsiElement element1, final PsiElement element2) { final PsiElement parent = PsiTreeUtil.findCommonParent(element1, element2); if (parent == null) { return null; @@ -136,5 +135,4 @@ public class PyExtractMethodHandler implements RefactoringActionHandler { } return null; } - } diff --git a/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java b/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java index bf8c95f91033..6a645a3ac704 100644 --- a/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java +++ b/python/src/com/jetbrains/python/refactoring/extractmethod/PyExtractMethodUtil.java @@ -2,6 +2,7 @@ package com.jetbrains.python.refactoring.extractmethod; import com.intellij.codeInsight.codeFragment.CodeFragment; import com.intellij.lang.LanguageNamesValidation; +import com.intellij.lang.refactoring.NamesValidator; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.editor.Editor; @@ -45,7 +46,6 @@ import java.util.Map; * @author oleg */ public class PyExtractMethodUtil { - public static final String NAME = "extract.method.name"; private PyExtractMethodUtil() { @@ -71,6 +71,9 @@ public class PyExtractMethodUtil { // collect statements final List elementsRange = PyPsiUtils.collectElements(statement1, statement2); if (elementsRange.isEmpty()) { + CommonRefactoringUtil.showErrorHint(project, editor, + "Cannot perform refactoring from empty code fragment", + RefactoringBundle.message("extract.method.title"), "refactoring.extractMethod"); return; } @@ -108,16 +111,17 @@ public class PyExtractMethodUtil { builder.append("(").append(createCallArgsString(variableData)).append(")"); PsiElement callElement = PyElementGenerator.getInstance(project).createFromText(LanguageLevel.getDefault(), PyCallExpression.class, builder.toString()); - //# replace statements with call + // Replace statements with call callElement = replaceElements(elementsRange, callElement); - // # Set editor + // Set editor setSelectionAndCaret(editor, callElement); } }); } }, "Extract method", null); - } else { + } + else { CommandProcessor.getInstance().executeCommand(project, new Runnable() { public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -210,8 +214,10 @@ public class PyExtractMethodUtil { if (fragment.getOutputVariables().isEmpty()) { CommandProcessor.getInstance().executeCommand(project, new Runnable() { + @Override public void run() { ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override public void run() { // Generate method PyFunction generatedMethod = generateMethodFromExpression(project, methodName, variableData, expression, flags); @@ -234,7 +240,9 @@ public class PyExtractMethodUtil { PsiElement callElement = fragment.isReturnInstructionInside() ? returnStatement : returnStatement.getExpression(); // replace statements with call - callElement = PyPsiUtils.replaceExpression(expression, callElement); + if (callElement != null) { + callElement = PyPsiUtils.replaceExpression(expression, callElement); + } // Set editor setSelectionAndCaret(editor, callElement); @@ -372,15 +380,18 @@ public class PyExtractMethodUtil { addFakeParameters(builder, variableData); final PyFunction method = builder.buildFunction(project, LanguageLevel.getDefault()); final PyStatementList statementList = method.getStatementList(); - + assert statementList != null; for (PsiElement element : elementsRange) { - if (element instanceof PsiWhiteSpace){ + if (element instanceof PsiWhiteSpace) { continue; } statementList.add(element); } // remove last instruction - statementList.getFirstChild().delete(); + final PsiElement child = statementList.getFirstChild(); + if (child != null) { + child.delete(); + } return method; } @@ -406,15 +417,15 @@ public class PyExtractMethodUtil { final PsiElement element, final boolean isClassMethod, final boolean isStaticMethod) { - final ExtractMethodValidator validator = new PyExtractMethodValidator(element, project); - if (ApplicationManager.getApplication().isUnitTestMode()){ + final ExtractMethodValidator validator = new PyExtractMethodValidator(element, project); + if (ApplicationManager.getApplication().isUnitTestMode()) { String name = System.getProperty(NAME); if (name == null){ name = "foo"; } final String error = validator.check(name); if (error != null){ - if (ApplicationManager.getApplication().isUnitTestMode()){ + if (ApplicationManager.getApplication().isUnitTestMode()) { throw new CommonRefactoringUtil.RefactoringErrorHintException(error); } final StringBuilder builder = new StringBuilder(); @@ -517,7 +528,9 @@ public class PyExtractMethodUtil { } public boolean isValidName(final String name) { - return LanguageNamesValidation.INSTANCE.forLanguage(PythonLanguage.getInstance()).isIdentifier(name, myProject); + final NamesValidator validator = LanguageNamesValidation.INSTANCE.forLanguage(PythonLanguage.getInstance()); + assert validator != null; + return validator.isIdentifier(name, myProject); } } } diff --git a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java index 3bce02aef7a3..d81877c29a17 100644 --- a/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java +++ b/python/src/com/jetbrains/python/refactoring/move/PyMoveFileHandler.java @@ -1,11 +1,13 @@ package com.jetbrains.python.refactoring.move; import com.intellij.openapi.util.Key; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.move.moveFilesOrDirectories.MoveFileHandler; import com.intellij.usageView.UsageInfo; import com.intellij.util.IncorrectOperationException; +import com.jetbrains.python.actions.CreatePackageAction; import com.jetbrains.python.codeInsight.imports.PyImportOptimizer; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyQualifiedName; @@ -33,6 +35,16 @@ public class PyMoveFileHandler extends MoveFileHandler { @Override public void prepareMovedFile(PsiFile file, PsiDirectory moveDestination, Map oldToNewMap) { + if (file != null) { + final List roots = PyUtil.getSourceRoots(file); + PsiDirectory root = moveDestination; + while (root != null && !roots.contains(root.getVirtualFile())) { + root = root.getParentDirectory(); + } + if (moveDestination != root && root != null) { + CreatePackageAction.createInitPyInHierarchy(moveDestination, root); + } + } // TODO: Update relative imports } diff --git a/python/src/com/jetbrains/python/sdk/IronPythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/IronPythonSdkFlavor.java index 6598c72b4907..bbb08aae87e9 100644 --- a/python/src/com/jetbrains/python/sdk/IronPythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/IronPythonSdkFlavor.java @@ -49,7 +49,7 @@ public class IronPythonSdkFlavor extends PythonSdkFlavor { @Override public String getVersionString(String sdkHome) { - return "IronPython " + getVersionFromOutput(sdkHome, "-V", "\\w+ ([0-9\\.]+).*", true); + return "IronPython " + getVersionFromOutput(sdkHome, "-V", "\\w+ ([0-9\\.]+).*"); } @Override diff --git a/python/src/com/jetbrains/python/sdk/JythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/JythonSdkFlavor.java index a3a7da4e822b..70e5b9624bac 100644 --- a/python/src/com/jetbrains/python/sdk/JythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/JythonSdkFlavor.java @@ -36,7 +36,7 @@ public class JythonSdkFlavor extends PythonSdkFlavor { @Override public String getVersionString(String sdkHome) { - return getVersionFromOutput(sdkHome, "--version", "(Jython \\S+)( on .*)?", false); + return getVersionFromOutput(sdkHome, "--version", "(Jython \\S+)( on .*)?"); } @Override diff --git a/python/src/com/jetbrains/python/sdk/PyPySdkFlavor.java b/python/src/com/jetbrains/python/sdk/PyPySdkFlavor.java index cf5ea8c54919..5f69d18c5ad2 100644 --- a/python/src/com/jetbrains/python/sdk/PyPySdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/PyPySdkFlavor.java @@ -21,6 +21,6 @@ public class PyPySdkFlavor extends PythonSdkFlavor { @Override public String getVersionString(String sdkHome) { - return getVersionFromOutput(sdkHome, "--version", "\\[(PyPy .+)\\]", true); + return getVersionFromOutput(sdkHome, "--version", "\\[(PyPy [^ ]+).*\\]"); } } diff --git a/python/src/com/jetbrains/python/sdk/PythonSdkFlavor.java b/python/src/com/jetbrains/python/sdk/PythonSdkFlavor.java index 7a1be292bb38..5a394f3f3e9d 100644 --- a/python/src/com/jetbrains/python/sdk/PythonSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/PythonSdkFlavor.java @@ -80,11 +80,11 @@ public abstract class PythonSdkFlavor { @Nullable public String getVersionString(String sdkHome) { - return getVersionFromOutput(sdkHome, "-V", "(Python \\S+).*", false); + return getVersionFromOutput(sdkHome, "-V", "(Python \\S+).*"); } @Nullable - protected static String getVersionFromOutput(String sdkHome, String version_opt, String version_regexp, boolean stdout) { + protected static String getVersionFromOutput(String sdkHome, String version_opt, String version_regexp) { 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}); @@ -97,8 +97,11 @@ public abstract class PythonSdkFlavor { ); return null; } - final List lines = stdout ? process_output.getStdoutLines() : process_output.getStderrLines(); - return SdkUtil.getFirstMatch(lines, pattern); + final String result = SdkUtil.getFirstMatch(process_output.getStderrLines(), pattern); + if (result != null) { + return result; + } + return SdkUtil.getFirstMatch(process_output.getStdoutLines(), pattern); } public Collection getExtraDebugOptions() { diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/namedTuple.py b/python/testData/inspections/PyUnresolvedReferencesInspection/namedTuple.py index 6be5439959d5..66b7904a60a3 100644 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/namedTuple.py +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/namedTuple.py @@ -10,3 +10,6 @@ print p.__add__ print p._asdict() print Point._fields print p._replace + +if isinstance(p, Point): + p.x \ No newline at end of file diff --git a/python/testData/refactoring/extractmethod/methodInIf.after.py b/python/testData/refactoring/extractmethod/methodInIf.after.py new file mode 100644 index 000000000000..56a5e579abfa --- /dev/null +++ b/python/testData/refactoring/extractmethod/methodInIf.after.py @@ -0,0 +1,10 @@ +class C: + def baz(self, arg_new): + self.bar(arg_new) + + def foo(self, option, arg): + if option: + self.baz(arg) + + def bar(self, arg): + pass \ No newline at end of file diff --git a/python/testData/refactoring/extractmethod/methodInIf.before.py b/python/testData/refactoring/extractmethod/methodInIf.before.py new file mode 100644 index 000000000000..c4011231c895 --- /dev/null +++ b/python/testData/refactoring/extractmethod/methodInIf.before.py @@ -0,0 +1,7 @@ +class C: + def foo(self, option, arg): + if option: + self.bar(arg) + + def bar(self, arg): + pass \ No newline at end of file diff --git a/python/testData/refactoring/move/moduleToNonPackage/after/src/a.py b/python/testData/refactoring/move/moduleToNonPackage/after/src/a.py new file mode 100644 index 000000000000..6618ac3cb7ca --- /dev/null +++ b/python/testData/refactoring/move/moduleToNonPackage/after/src/a.py @@ -0,0 +1,7 @@ +from nonp3 import m1 +from nonp3.m1 import foo + +m1.foo +m1.bar +m1 +foo \ No newline at end of file diff --git a/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/__init__.py b/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/__init__.py new file mode 100644 index 000000000000..09ee69e66c3c --- /dev/null +++ b/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/__init__.py @@ -0,0 +1 @@ +__author__ = 'user1' diff --git a/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/m1.py b/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/m1.py new file mode 100644 index 000000000000..cb19528f954f --- /dev/null +++ b/python/testData/refactoring/move/moduleToNonPackage/after/src/nonp3/m1.py @@ -0,0 +1,2 @@ +foo = 42 +bar = -1 \ No newline at end of file diff --git a/python/testData/refactoring/move/moduleToNonPackage/after/src/p1/__init__.py b/python/testData/refactoring/move/moduleToNonPackage/after/src/p1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/moduleToNonPackage/after/src/p1/p2/__init__.py b/python/testData/refactoring/move/moduleToNonPackage/after/src/p1/p2/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/moduleToNonPackage/before/src/a.py b/python/testData/refactoring/move/moduleToNonPackage/before/src/a.py new file mode 100644 index 000000000000..89193abbbec7 --- /dev/null +++ b/python/testData/refactoring/move/moduleToNonPackage/before/src/a.py @@ -0,0 +1,9 @@ +from p1.p2 import m1 +from p1.p2.m1 import foo +import p1.p2.m1 +import p1 + +p1.p2.m1.foo +m1.bar +m1 +foo \ No newline at end of file diff --git a/python/testData/refactoring/move/moduleToNonPackage/before/src/p1/__init__.py b/python/testData/refactoring/move/moduleToNonPackage/before/src/p1/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/moduleToNonPackage/before/src/p1/p2/__init__.py b/python/testData/refactoring/move/moduleToNonPackage/before/src/p1/p2/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testData/refactoring/move/moduleToNonPackage/before/src/p1/p2/m1.py b/python/testData/refactoring/move/moduleToNonPackage/before/src/p1/p2/m1.py new file mode 100644 index 000000000000..cb19528f954f --- /dev/null +++ b/python/testData/refactoring/move/moduleToNonPackage/before/src/p1/p2/m1.py @@ -0,0 +1,2 @@ +foo = 42 +bar = -1 \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java b/python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java index 1813b4382728..de00757ce9db 100644 --- a/python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java +++ b/python/testSrc/com/jetbrains/python/fixtures/PyCommandLineTestCase.java @@ -26,7 +26,7 @@ public abstract class PyCommandLineTestCase extends PyTestCase { protected static int verifyPyDevDParameters(List params) { params = Lists.newArrayList(params); - int debugParam = params.remove("--DEBUG_RECORD_SOCKET_READS") ? 1 : 0; + int debugParam = params.remove("--DEBUG") ? 1 : 0; assertEquals(PythonHelpersLocator.getHelperPath("pydev/pydevd.py"), params.get(0)); assertEquals("--client", params.get(1)); assertEquals("--port", params.get(3)); diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyExtractMethodTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyExtractMethodTest.java index dabbf42061bf..2827d4b074de 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyExtractMethodTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyExtractMethodTest.java @@ -147,4 +147,9 @@ public class PyExtractMethodTest extends LightMarkedTestCase { public void testStaticMethod() { doTest("staticmethod.before.py", "baz", "staticmethod.after.py"); } + + // PY-5123 + public void testMethodInIf() { + doTest("methodInIf.before.py", "baz", "methodInIf.after.py"); + } } diff --git a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java index 8451e7f720a3..67d03802aadc 100644 --- a/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java +++ b/python/testSrc/com/jetbrains/python/refactoring/PyMoveTest.java @@ -75,6 +75,11 @@ public class PyMoveTest extends PyTestCase { doMoveFileTest("p1/p2/m1.py", "p1"); } + // PY-5168 + public void testModuleToNonPackage() { + doMoveFileTest("p1/p2/m1.py", "nonp3"); + } + private void doMoveFileTest(String fileName, String toDirName) { Project project = myFixture.getProject(); PsiManager manager = PsiManager.getInstance(project);