diff --git a/python/helpers/pycharm/attestrunner.py b/python/helpers/pycharm/attestrunner.py index 3a92cf82ef99..3bab7e294277 100644 --- a/python/helpers/pycharm/attestrunner.py +++ b/python/helpers/pycharm/attestrunner.py @@ -1,8 +1,17 @@ -import sys, os, imp, re, inspect -from utrunner import debug -from nose_helper.util import func_lineno -import traceback +import sys, os +import imp + from tcunittest import TeamcityTestResult + +from pycharm_run_utils import import_system_module +from pycharm_run_utils import adjust_sys_path +from pycharm_run_utils import debug, getModuleName + +adjust_sys_path() + +re = import_system_module("re") +inspect = import_system_module("inspect") + try: from attest.reporters import AbstractReporter from attest.collectors import Tests @@ -11,113 +20,113 @@ except: raise NameError("Please, install attests") class TeamCityReporter(AbstractReporter, TeamcityTestResult): - """Teamcity reporter for attests.""" + """Teamcity reporter for attests.""" - def __init__(self, prefix): - TeamcityTestResult.__init__(self) - self.prefix = prefix - - def begin(self, tests): - """initialize suite stack and count tests""" - self.total = len(tests) - self.suite_stack = [] - self.messages.testCount(self.total) + def __init__(self, prefix): + TeamcityTestResult.__init__(self) + self.prefix = prefix - def success(self, result): - """called when test finished successfully""" - suite = self.get_suite_name(result.test) - self.start_suite(suite) - name = self.get_test_name(result) - self.start_test(result, name) - self.messages.testFinished(name) + def begin(self, tests): + """initialize suite stack and count tests""" + self.total = len(tests) + self.suite_stack = [] + self.messages.testCount(self.total) - def failure(self, result): - """called when test failed""" - suite = self.get_suite_name(result.test) - self.start_suite(suite) - name = self.get_test_name(result) - self.start_test(result, name) - exctype, value, tb = result.exc_info - error_value = self.find_error_value(tb) - if (error_value.startswith("'") or error_value.startswith('"')) and \ - (error_value.endswith("'") or error_value.endswith('"')): - first = self._unescape(self.find_first(error_value)) - second = self._unescape(self.find_second(error_value)) - else: - first = second = "" + def success(self, result): + """called when test finished successfully""" + suite = self.get_suite_name(result.test) + self.start_suite(suite) + name = self.get_test_name(result) + self.start_test(result, name) + self.messages.testFinished(name) - err = self.formatErr(result.exc_info) - if isinstance(result.error, AssertionError): - self.messages.testFailed(name, message='Failure', - details=err, - expected=first, actual=second) - else: - self.messages.testError(name, message='Error', - details=err) + def failure(self, result): + """called when test failed""" + suite = self.get_suite_name(result.test) + self.start_suite(suite) + name = self.get_test_name(result) + self.start_test(result, name) + exctype, value, tb = result.exc_info + error_value = self.find_error_value(tb) + if (error_value.startswith("'") or error_value.startswith('"')) and\ + (error_value.endswith("'") or error_value.endswith('"')): + first = self._unescape(self.find_first(error_value)) + second = self._unescape(self.find_second(error_value)) + else: + first = second = "" - def finished(self): - """called when all tests finished""" - self.end_last_suite() - for suite in self.suite_stack[::-1]: - self.messages.testSuiteFinished(suite) + err = self.formatErr(result.exc_info) + if isinstance(result.error, AssertionError): + self.messages.testFailed(name, message='Failure', + details=err, + expected=first, actual=second) + else: + self.messages.testError(name, message='Error', + details=err) - def get_test_name(self, result): - name = result.test_name - ind = name.find("%") #remove unique module prefix - if ind != -1: - name = name[:ind]+name[name.find(".", ind):] - return name - - def end_last_suite(self): + def finished(self): + """called when all tests finished""" + self.end_last_suite() + for suite in self.suite_stack[::-1]: + self.messages.testSuiteFinished(suite) + + def get_test_name(self, result): + name = result.test_name + ind = name.find("%") #remove unique module prefix + if ind != -1: + name = name[:ind]+name[name.find(".", ind):] + return name + + def end_last_suite(self): + if self.current_suite: + self.messages.testSuiteFinished(self.current_suite) + self.current_suite = None + + def get_suite_name(self, test): + module = inspect.getmodule(test) + klass = getattr(test, "im_class", None) + file = module.__file__ + if file.endswith("pyc"): + file = file[:-1] + + suite = module.__name__ + if self.prefix: + tmp = file[:-3] + ind = tmp.split(self.prefix)[1] + suite = ind.replace("/", ".") + if klass: + suite += "." + klass.__name__ + lineno = inspect.getsourcelines(klass) + else: + lineno = ("", 1) + + return (suite, file+":"+str(lineno[1])) + + def start_suite(self, suite_info): + """finish previous suite and put current suite + to stack""" + suite, file = suite_info + if suite != self.current_suite: if self.current_suite: - self.messages.testSuiteFinished(self.current_suite) - self.current_suite = None + if suite.startswith(self.current_suite+"."): + self.suite_stack.append(self.current_suite) + else: + self.messages.testSuiteFinished(self.current_suite) + for s in self.suite_stack: + if not suite.startswith(s+"."): + self.current_suite = s + self.messages.testSuiteFinished(self.current_suite) + else: + break + self.current_suite = suite + self.messages.testSuiteStarted(self.current_suite, location="file://" + file) - def get_suite_name(self, test): - module = inspect.getmodule(test) - klass = getattr(test, "im_class", None) - file = module.__file__ - if file.endswith("pyc"): - file = file[:-1] - - suite = module.__name__ - if self.prefix: - tmp = file[:-3] - ind = tmp.split(self.prefix)[1] - suite = ind.replace("/", ".") - if klass: - suite += "." + klass.__name__ - lineno = inspect.getsourcelines(klass) - else: - lineno = ("", 1) - - return (suite, file+":"+str(lineno[1])) - - def start_suite(self, suite_info): - """finish previous suite and put current suite - to stack""" - suite, file = suite_info - if suite != self.current_suite: - if self.current_suite: - if suite.startswith(self.current_suite+"."): - self.suite_stack.append(self.current_suite) - else: - self.messages.testSuiteFinished(self.current_suite) - for s in self.suite_stack: - if not suite.startswith(s+"."): - self.current_suite = s - self.messages.testSuiteFinished(self.current_suite) - else: - break - self.current_suite = suite - self.messages.testSuiteStarted(self.current_suite, location="file://" + file) - - def start_test(self, result, name): - """trying to find test location """ - real_func = result.test.func_closure[0].cell_contents - lineno = inspect.getsourcelines(real_func) - file = inspect.getsourcefile(real_func) - self.messages.testStarted(name, "file://"+file+":"+str(lineno[1])) + def start_test(self, result, name): + """trying to find test location """ + real_func = result.test.func_closure[0].cell_contents + lineno = inspect.getsourcelines(real_func) + file = inspect.getsourcefile(real_func) + self.messages.testStarted(name, "file://"+file+":"+str(lineno[1])) def get_subclasses(module, base_class=TestBase): test_classes = [] @@ -238,13 +247,13 @@ def process_args(): # From method in class or from function module = get_module(argument_list[0]) if argument_list[1] == "": - debug("/ from function " + argument_list[2] + " in " + argument_list[0]) - # test function, not method - test = getattr(module, argument_list[2]) + debug("/ from function " + argument_list[2] + " in " + argument_list[0]) + # test function, not method + test = getattr(module, argument_list[2]) else: - debug("/ from method " + argument_list[2] + " in class " + argument_list[1] + " in " + argument_list[0]) - klass = getattr(module, argument_list[1]) - test = getattr(klass(), argument_list[2]) + debug("/ from method " + argument_list[2] + " in class " + argument_list[1] + " in " + argument_list[0]) + klass = getattr(module, argument_list[1]) + test = getattr(klass(), argument_list[2]) tests.register([test]) tests.run(reporter=TeamCityReporter(prefix)) diff --git a/python/helpers/pycharm/django_manage.py b/python/helpers/pycharm/django_manage.py index bdc2571ceb30..376be035218b 100644 --- a/python/helpers/pycharm/django_manage.py +++ b/python/helpers/pycharm/django_manage.py @@ -1,10 +1,12 @@ #!/usr/bin/env python import sys -base_path = sys.argv.pop() -sys.path.insert(0, base_path) -from fix_getpass import fixGetpass import os -from django.core.management import execute_manager + +from pycharm_run_utils import adjust_django_sys_path +from fix_getpass import fixGetpass + +adjust_django_sys_path() +base_path = sys.argv.pop() try: from runpy import run_module @@ -17,6 +19,6 @@ if not manage_file: if __name__ == "__main__": - fixGetpass() - run_module(manage_file, None, '__main__', True) + fixGetpass() + run_module(manage_file, None, '__main__', True) diff --git a/python/helpers/pycharm/django_test_manage.py b/python/helpers/pycharm/django_test_manage.py index 13cbe35698bb..ae08cdd50248 100644 --- a/python/helpers/pycharm/django_test_manage.py +++ b/python/helpers/pycharm/django_test_manage.py @@ -1,11 +1,19 @@ #!/usr/bin/env python -from django.core.management import ManagementUtility -import inspect -import os -import sys +import os, sys + +from django.core.management import ManagementUtility + +from pycharm_run_utils import import_system_module + +inspect = import_system_module("inspect") + +import django_test_runner project_directory = sys.argv.pop() -sys.path.insert(0, project_directory) + +from django.core import management +from django.core.management.commands.test import Command +from django.conf import settings try: # setup environment @@ -13,12 +21,11 @@ try: sys.path.append(os.path.join(project_directory, os.pardir)) project_name = os.path.basename(project_directory) __import__(project_name) - sys.path.pop() except ImportError: # project has custom structure (project directory is not importable) pass - -os.chdir(project_directory) +finally: + sys.path.pop() manage_file = os.getenv('PYCHARM_DJANGO_MANAGE_MODULE') if not manage_file: @@ -33,9 +40,6 @@ settings_file = os.getenv('DJANGO_SETTINGS_MODULE') if not settings_file: settings_file = 'settings' -from django.core import management -from django.core.management.commands.test import Command -from django.conf import settings class PycharmTestCommand(Command): def get_runner(self): @@ -110,4 +114,5 @@ if __name__ == "__main__": utility = PycharmTestManagementUtility(sys.argv) else: utility = ManagementUtility() + utility.execute() \ No newline at end of file diff --git a/python/helpers/pycharm/django_test_runner.py b/python/helpers/pycharm/django_test_runner.py index 6e1d94cf4ea2..fa01aa100574 100644 --- a/python/helpers/pycharm/django_test_runner.py +++ b/python/helpers/pycharm/django_test_runner.py @@ -1,11 +1,20 @@ -from tcunittest import TeamcityTestRunner -from django.test.simple import build_suite, build_test, settings, get_app, get_apps, setup_test_environment, teardown_test_environment -import unittest -from django.test.testcases import TestCase -from tcmessages import TeamcityServiceMessages -import django import sys +from tcunittest import TeamcityTestRunner +from tcmessages import TeamcityServiceMessages + +from pycharm_run_utils import adjust_django_sys_path +from pycharm_run_utils import import_system_module + +adjust_django_sys_path() +unittest = import_system_module("unittest") + +from django.test.simple import build_suite, build_test, settings, get_app, get_apps, setup_test_environment, teardown_test_environment +from django.test.testcases import TestCase +from django.utils import unittest +from django import VERSION + + def get_test_suite_runner(): if hasattr(settings, "TEST_RUNNER"): from django.test.utils import get_runner @@ -83,9 +92,9 @@ class DjangoTeamcityTestRunner(BaseRunner): def run_tests(self, test_labels, extra_tests=None, **kwargs): if hasattr(settings, "TEST_RUNNER") and "NoseTestSuiteRunner" in settings.TEST_RUNNER: return super(DjangoTeamcityTestRunner, self).run_tests(test_labels, - extra_tests) + extra_tests) return super(DjangoTeamcityTestRunner, self).run_tests(test_labels, - extra_tests, **kwargs) + extra_tests, **kwargs) def partition_suite(suite, classes, bins): @@ -148,7 +157,7 @@ def run_tests(test_labels, verbosity=1, interactive=False, extra_tests=[], Returns the number of tests that failed. """ TeamcityServiceMessages(sys.stdout).testMatrixEntered() - if django.VERSION[1] > 1: + if VERSION[1] > 1: return DjangoTeamcityTestRunner().run_tests(test_labels, extra_tests=extra_tests, **kwargs) diff --git a/python/helpers/pycharm/docrunner.py b/python/helpers/pycharm/docrunner.py index 62e068d16ffa..37c4e3459e5f 100644 --- a/python/helpers/pycharm/docrunner.py +++ b/python/helpers/pycharm/docrunner.py @@ -1,181 +1,187 @@ -import os import imp import sys -import re -import doctest -import traceback import datetime from tcunittest import TeamcityTestResult from tcmessages import TeamcityServiceMessages +from pycharm_run_utils import import_system_module +from pycharm_run_utils import adjust_sys_path, debug, getModuleName, PYTHON_VERSION_MAJOR + +adjust_sys_path() + +os = import_system_module("os") +re = import_system_module("re") +doctest = import_system_module("doctest") +traceback = import_system_module("traceback") + class TeamcityDocTestResult(TeamcityTestResult): - """ - DocTests Result extends TeamcityTestResult, - overrides some methods, specific for doc tests, - such as getTestName, getTestId. - """ - def getTestName(self, test): + """ + DocTests Result extends TeamcityTestResult, + overrides some methods, specific for doc tests, + such as getTestName, getTestId. + """ + def getTestName(self, test): + name = self.current_suite.name + test.source + return name + + def getSuiteName(self, suite): + if test.source.rfind(".") == -1: name = self.current_suite.name + test.source - return name + else: + name = test.source + return name - def getSuiteName(self, suite): - if test.source.rfind(".") == -1: - name = self.current_suite.name + test.source - else: - name = test.source - return name + def getTestId(self, test): + file = os.path.realpath(self.current_suite.filename) + return "file://" + file + ":" + str( self.current_suite.lineno + test.lineno) - def getTestId(self, test): - file = os.path.realpath(self.current_suite.filename) - return "file://" + file + ":" + str( self.current_suite.lineno + test.lineno) + def getSuiteLocation(self): + file = os.path.realpath(self.current_suite.filename) + location = "file://" + file + if self.current_suite.lineno: + location += ":" + str(self.current_suite.lineno) + return location - def getSuiteLocation(self): - file = os.path.realpath(self.current_suite.filename) - location = "file://" + file - if self.current_suite.lineno: - location += ":" + str(self.current_suite.lineno) - return location + def startTest(self, test): + setattr(test, "startTime", datetime.datetime.now()) + id = self.getTestId(test) + self.messages.testStarted(self.getTestName(test), location=id) - def startTest(self, test): - setattr(test, "startTime", datetime.datetime.now()) - id = self.getTestId(test) - self.messages.testStarted(self.getTestName(test), location=id) + def startSuite(self, suite): + self.current_suite = suite + self.messages.testSuiteStarted(suite.name, location=self.getSuiteLocation()) - def startSuite(self, suite): - self.current_suite = suite - self.messages.testSuiteStarted(suite.name, location=self.getSuiteLocation()) + def stopSuite(self, suite): + self.messages.testSuiteFinished(suite.name) - def stopSuite(self, suite): - self.messages.testSuiteFinished(suite.name) + def addFailure(self, test, err = ''): + self.messages.testFailed(self.getTestName(test), + message='Failure', details=err) - def addFailure(self, test, err = ''): - self.messages.testFailed(self.getTestName(test), - message='Failure', details=err) - - def addError(self, test, err = ''): - self.messages.testError(self.getTestName(test), - message='Error', details=err) + def addError(self, test, err = ''): + self.messages.testError(self.getTestName(test), + message='Error', details=err) class DocTestRunner(doctest.DocTestRunner): - """ - Special runner for doctests, - overrides __run method to report results using TeamcityDocTestResult - """ - def __init__(self, verbose=None, optionflags=0): - doctest.DocTestRunner.__init__(self, verbose, optionflags) - self.stream = sys.stdout - self.result = TeamcityDocTestResult(self.stream) - #self.result.messages.testMatrixEntered() - self._tests = [] + """ + Special runner for doctests, + overrides __run method to report results using TeamcityDocTestResult + """ + def __init__(self, verbose=None, optionflags=0): + doctest.DocTestRunner.__init__(self, verbose, optionflags) + self.stream = sys.stdout + self.result = TeamcityDocTestResult(self.stream) + #self.result.messages.testMatrixEntered() + self._tests = [] - def addTests(self, tests): - self._tests.extend(tests) + def addTests(self, tests): + self._tests.extend(tests) - def addTest(self, test): - self._tests.append(test) + def addTest(self, test): + self._tests.append(test) - def countTests(self): - return len(self._tests) + def countTests(self): + return len(self._tests) - def start(self): - for test in self._tests: - self.run(test) + def start(self): + for test in self._tests: + self.run(test) - def __run(self, test, compileflags, out): - failures = tries = 0 + def __run(self, test, compileflags, out): + failures = tries = 0 - original_optionflags = self.optionflags - SUCCESS, FAILURE, BOOM = range(3) # `outcome` state - check = self._checker.check_output - self.result.startSuite(test) - for examplenum, example in enumerate(test.examples): + original_optionflags = self.optionflags + SUCCESS, FAILURE, BOOM = range(3) # `outcome` state + check = self._checker.check_output + self.result.startSuite(test) + for examplenum, example in enumerate(test.examples): - quiet = (self.optionflags & doctest.REPORT_ONLY_FIRST_FAILURE and - failures > 0) + quiet = (self.optionflags & doctest.REPORT_ONLY_FIRST_FAILURE and + failures > 0) - self.optionflags = original_optionflags - if example.options: - for (optionflag, val) in example.options.items(): - if val: - self.optionflags |= optionflag - else: - self.optionflags &= ~optionflag + self.optionflags = original_optionflags + if example.options: + for (optionflag, val) in example.options.items(): + if val: + self.optionflags |= optionflag + else: + self.optionflags &= ~optionflag - if hasattr(doctest, 'SKIP'): - if self.optionflags & doctest.SKIP: - continue + if hasattr(doctest, 'SKIP'): + if self.optionflags & doctest.SKIP: + continue - tries += 1 - if not quiet: - self.report_start(out, test, example) + tries += 1 + if not quiet: + self.report_start(out, test, example) - filename = '' % (test.name, examplenum) + filename = '' % (test.name, examplenum) - try: - exec(compile(example.source, filename, "single", - compileflags, 1), test.globs) - self.debugger.set_continue() # ==== Example Finished ==== - exception = None - except KeyboardInterrupt: - raise - except: - exception = sys.exc_info() - self.debugger.set_continue() # ==== Example Finished ==== + try: + exec(compile(example.source, filename, "single", + compileflags, 1), test.globs) + self.debugger.set_continue() # ==== Example Finished ==== + exception = None + except KeyboardInterrupt: + raise + except: + exception = sys.exc_info() + self.debugger.set_continue() # ==== Example Finished ==== - got = self._fakeout.getvalue() # the actual output - self._fakeout.truncate(0) - outcome = FAILURE # guilty until proved innocent or insane + got = self._fakeout.getvalue() # the actual output + self._fakeout.truncate(0) + outcome = FAILURE # guilty until proved innocent or insane - if exception is None: - if check(example.want, got, self.optionflags): - outcome = SUCCESS + if exception is None: + if check(example.want, got, self.optionflags): + outcome = SUCCESS - else: - exc_msg = traceback.format_exception_only(*exception[:2])[-1] - if not quiet: - got += doctest._exception_traceback(exception) + else: + exc_msg = traceback.format_exception_only(*exception[:2])[-1] + if not quiet: + got += doctest._exception_traceback(exception) - if example.exc_msg is None: - outcome = BOOM + if example.exc_msg is None: + outcome = BOOM - elif check(example.exc_msg, exc_msg, self.optionflags): - outcome = SUCCESS + elif check(example.exc_msg, exc_msg, self.optionflags): + outcome = SUCCESS - elif self.optionflags & doctest.IGNORE_EXCEPTION_DETAIL: - m1 = re.match(r'[^:]*:', example.exc_msg) - m2 = re.match(r'[^:]*:', exc_msg) - if m1 and m2 and check(m1.group(0), m2.group(0), - self.optionflags): - outcome = SUCCESS + elif self.optionflags & doctest.IGNORE_EXCEPTION_DETAIL: + m1 = re.match(r'[^:]*:', example.exc_msg) + m2 = re.match(r'[^:]*:', exc_msg) + if m1 and m2 and check(m1.group(0), m2.group(0), + self.optionflags): + outcome = SUCCESS - # Report the outcome. - if outcome is SUCCESS: - self.result.startTest(example) - self.result.stopTest(example) - elif outcome is FAILURE: - self.result.startTest(example) - err = self._failure_header(test, example) +\ - self._checker.output_difference(example, got, self.optionflags) - self.result.addFailure(example, err) + # Report the outcome. + if outcome is SUCCESS: + self.result.startTest(example) + self.result.stopTest(example) + elif outcome is FAILURE: + self.result.startTest(example) + err = self._failure_header(test, example) +\ + self._checker.output_difference(example, got, self.optionflags) + self.result.addFailure(example, err) - elif outcome is BOOM: - self.result.startTest(example) - err=self._failure_header(test, example) + \ - 'Exception raised:\n' + doctest._indent(doctest._exception_traceback(exception)) - self.result.addError(example, err) + elif outcome is BOOM: + self.result.startTest(example) + err=self._failure_header(test, example) +\ + 'Exception raised:\n' + doctest._indent(doctest._exception_traceback(exception)) + self.result.addError(example, err) - else: - assert False, ("unknown outcome", outcome) + else: + assert False, ("unknown outcome", outcome) - self.optionflags = original_optionflags + self.optionflags = original_optionflags - self.result.stopSuite(test) + self.result.stopSuite(test) modules = {} -from utrunner import debug, getModuleName, PYTHON_VERSION_MAJOR + runner = DocTestRunner() @@ -238,7 +244,7 @@ def testFilesInFolderUsingPattern(folder, pattern = ".*"): if name.endswith(".py"): modules.append(loadSource(path)) elif not name.endswith(".pyc") and not name.endswith("$py.class")\ - and os.path.isfile(path): + and os.path.isfile(path): testfile(path) for module in modules: @@ -246,7 +252,7 @@ def testFilesInFolderUsingPattern(folder, pattern = ".*"): result.append(module) return result -if __name__ == "__main__": +if __name__ == "__main__": finder = doctest.DocTestFinder() for arg in sys.argv[1:]: @@ -272,10 +278,10 @@ if __name__ == "__main__": debug("/ from module " + a[0]) # for doctests from non-python file if a[0].rfind(".py") == -1: - testfile(a[0]) - modules = [] + testfile(a[0]) + modules = [] else: - modules = [loadSource(a[0])] + modules = [loadSource(a[0])] # for doctests for module in modules: @@ -304,26 +310,26 @@ if __name__ == "__main__": except SyntaxError: raise NameError('File "%s" is not python file' % (a[0], )) if a[1] == "": - # test function, not method - debug("/ from method " + a[2] + " in " + a[0]) - if hasattr(module, a[2]): - testcase = getattr(module, a[2]) + # test function, not method + debug("/ from method " + a[2] + " in " + a[0]) + if hasattr(module, a[2]): + testcase = getattr(module, a[2]) + tests = finder.find(testcase, testcase.__name__) + runner.addTests(tests) + else: + raise NameError('Module "%s" has no method "%s"' % (a[0], a[2])) + else: + debug("/ from method " + a[2] + " in class " + a[1] + " in " + a[0]) + if hasattr(module, a[1]): + testCaseClass = getattr(module, a[1]) + if hasattr(testCaseClass, a[2]): + testcase = getattr(testCaseClass, a[2]) tests = finder.find(testcase, testcase.__name__) runner.addTests(tests) else: - raise NameError('Module "%s" has no method "%s"' % (a[0], a[2])) - else: - debug("/ from method " + a[2] + " in class " + a[1] + " in " + a[0]) - if hasattr(module, a[1]): - testCaseClass = getattr(module, a[1]) - if hasattr(testCaseClass, a[2]): - testcase = getattr(testCaseClass, a[2]) - tests = finder.find(testcase, testcase.__name__) - runner.addTests(tests) - else: - raise NameError('Class "%s" has no function "%s"' % (testCaseClass, a[2])) - else: - raise NameError('Module "%s" has no class "%s"' % (module, a[1])) + raise NameError('Class "%s" has no function "%s"' % (testCaseClass, a[2])) + else: + raise NameError('Module "%s" has no class "%s"' % (module, a[1])) debug("/ Loaded " + str(runner.countTests()) + " tests") TeamcityServiceMessages(sys.stdout).testCount(runner.countTests()) diff --git a/python/helpers/pycharm/noserunner.py b/python/helpers/pycharm/noserunner.py index 3775091c23dc..32079dbb6ee0 100644 --- a/python/helpers/pycharm/noserunner.py +++ b/python/helpers/pycharm/noserunner.py @@ -1,7 +1,14 @@ -import sys, shlex -from utrunner import debug +import sys + from nose_utils import TeamcityPlugin +from pycharm_run_utils import debug, import_system_module +from pycharm_run_utils import adjust_sys_path + +adjust_sys_path(False) + +shlex = import_system_module("shlex") + try: from nose.core import TestProgram from nose.config import Config diff --git a/python/helpers/pycharm/pycharm_run_utils.py b/python/helpers/pycharm/pycharm_run_utils.py new file mode 100644 index 000000000000..a70e74ad02ca --- /dev/null +++ b/python/helpers/pycharm/pycharm_run_utils.py @@ -0,0 +1,42 @@ +__author__ = 'ktisha' +import os, sys +import imp + +PYTHON_VERSION_MAJOR = sys.version_info[0] +PYTHON_VERSION_MINOR = sys.version_info[1] + +ENABLE_DEBUG_LOGGING = False +if os.getenv("UTRUNNER_ENABLE_DEBUG_LOGGING"): + ENABLE_DEBUG_LOGGING = True + +def debug(what): + if ENABLE_DEBUG_LOGGING: + sys.stdout.writelines(str(what) + '\n') + +def adjust_sys_path(add_script_parent=True, script_index=1): + sys.path.pop(0) + if add_script_parent: + script_path = os.path.dirname(sys.argv[script_index]) + sys.path.insert(0, script_path) + +def adjust_django_sys_path(): + sys.path.pop(0) + script_path = sys.argv[-1] + sys.path.insert(0, script_path) + +def import_system_module(name): + lib_path = os.path.dirname(sys.modules['os'].__file__) + + module_path = os.path.join(lib_path, name + '.py') + if not os.path.exists(module_path): + module_path = os.path.join(lib_path, name + '/') + + if os.path.exists(module_path): + return imp.load_source('pycharm_' + name, module_path) + + return None + +def getModuleName(prefix, cnt): + return prefix + "%" + str(cnt) + + diff --git a/python/helpers/pycharm/pytest_teamcity.py b/python/helpers/pycharm/pytest_teamcity.py index c4874b6fa528..ca7e7371fad6 100644 --- a/python/helpers/pycharm/pytest_teamcity.py +++ b/python/helpers/pycharm/pytest_teamcity.py @@ -1,6 +1,9 @@ from tcmessages import TeamcityServiceMessages import os -import sys + +from pycharm_run_utils import adjust_sys_path + +adjust_sys_path(False) messages = TeamcityServiceMessages(prepend_linebreak=True) messages.testMatrixEntered() @@ -15,7 +18,7 @@ def get_name(nodeid): return nodeid.split("::")[-1] def fspath_to_url(fspath): - return "file:///" + str(fspath).replace("\\", "/") + return "file:///" + str(fspath).replace("\\", "/") if PYVERSION > [1, 4, 0]: items = {} @@ -74,7 +77,7 @@ if PYVERSION > [1, 4, 0]: elif report.failed: messages.testFailed(name, details=report.longrepr) elif report.when == "call": - messages.testFinished(name) + messages.testFinished(name) def pytest_sessionfinish(session, exitstatus): if current_suite: @@ -113,7 +116,7 @@ else: fspath, lineno, msg = item.reportinfo() url = fspath_to_url(fspath) if lineno: url += ":" + str(lineno) - # messages.testStarted(item.name, location=url) + # messages.testStarted(item.name, location=url) def pytest_runtest_logreport(report): if report.item._args: diff --git a/python/helpers/pycharm/utrunner.py b/python/helpers/pycharm/utrunner.py index 098da3f6643d..2274c705a39b 100644 --- a/python/helpers/pycharm/utrunner.py +++ b/python/helpers/pycharm/utrunner.py @@ -1,27 +1,17 @@ -import os -import imp import sys -import types -import re -from tcmessages import TeamcityServiceMessages +import imp from tcunittest import TeamcityTestRunner - from nose_helper import TestLoader, ContextSuite +from pycharm_run_utils import import_system_module +from pycharm_run_utils import adjust_sys_path +from pycharm_run_utils import debug, getModuleName, PYTHON_VERSION_MAJOR -PYTHON_VERSION_MAJOR = sys.version_info[0] -PYTHON_VERSION_MINOR = sys.version_info[1] +adjust_sys_path() -ENABLE_DEBUG_LOGGING = False -if os.getenv("UTRUNNER_ENABLE_DEBUG_LOGGING"): - ENABLE_DEBUG_LOGGING = True - -def debug(what): - if ENABLE_DEBUG_LOGGING: - sys.stdout.writelines(str(what) + '\n') +os = import_system_module("os") +re = import_system_module("re") modules = {} -def getModuleName(prefix, cnt): - return prefix + "%" + str(cnt) def loadSource(fileName): baseName = os.path.basename(fileName) @@ -30,7 +20,7 @@ def loadSource(fileName): # for users wanted to run unittests under django #because of django took advantage of module name settings_file = os.getenv('DJANGO_SETTINGS_MODULE') - if settings_file and moduleName=="models": + if settings_file and moduleName == "models": baseName = os.path.realpath(fileName) moduleName = ".".join((baseName.split(os.sep)[-2], "models")) @@ -54,7 +44,7 @@ def walkModules(modulesAndPattern, dirname, names): if name.endswith(".py") and prog.match(name): modules.append(loadSource(os.path.join(dirname, name))) -def loadModulesFromFolderRec(folder, pattern="test.*"): +def loadModulesFromFolderRec(folder, pattern = "test.*"): modules = [] if PYTHON_VERSION_MAJOR == 3: prog_list = [re.compile(pat.strip()) for pat in pattern.split(',')] @@ -77,6 +67,7 @@ def setLoader(module): try: module.__getattribute__('unittest2') import unittest2 + testLoader = unittest2.TestLoader() all = unittest2.TestSuite() except: @@ -86,6 +77,7 @@ if __name__ == "__main__": arg = sys.argv[-1] if arg == "true": import unittest + testLoader = unittest.TestLoader() all = unittest.TestSuite() pure_unittest = True @@ -129,24 +121,25 @@ if __name__ == "__main__": if pure_unittest: all.addTests(testLoader.loadTestsFromTestCase(getattr(module, a[1]))) else: - all.addTests(testLoader.loadTestsFromTestClass(getattr(module, a[1])), getattr(module, a[1])) + all.addTests(testLoader.loadTestsFromTestClass(getattr(module, a[1])), + getattr(module, a[1])) else: # From method in class or from function - debug("/ from method " + a[2] + " in testcase " + a[1] + " in " + a[0]) + debug("/ from method " + a[2] + " in testcase " + a[1] + " in " + a[0]) module = loadSource(a[0]) setLoader(module) if a[1] == "": - # test function, not method - all.addTest(testLoader.makeTest(getattr(module, a[2]))) + # test function, not method + all.addTest(testLoader.makeTest(getattr(module, a[2]))) else: - testCaseClass = getattr(module, a[1]) - try: - all.addTest(testCaseClass(a[2])) - except: - # class is not a testcase inheritor - all.addTest(testLoader.makeTest(getattr(testCaseClass, a[2]), testCaseClass)) - + testCaseClass = getattr(module, a[1]) + try: + all.addTest(testCaseClass(a[2])) + except: + # class is not a testcase inheritor + all.addTest( + testLoader.makeTest(getattr(testCaseClass, a[2]), testCaseClass)) debug("/ Loaded " + str(all.countTestCases()) + " tests") - TeamcityTestRunner().run(all, **options) \ No newline at end of file + TeamcityTestRunner().run(all, **options) diff --git a/python/openapi/src/com/jetbrains/python/run/AbstractPythonRunConfigurationParams.java b/python/openapi/src/com/jetbrains/python/run/AbstractPythonRunConfigurationParams.java index 7a0f0bd6d9af..88fa1f9b82e0 100644 --- a/python/openapi/src/com/jetbrains/python/run/AbstractPythonRunConfigurationParams.java +++ b/python/openapi/src/com/jetbrains/python/run/AbstractPythonRunConfigurationParams.java @@ -44,4 +44,9 @@ public interface AbstractPythonRunConfigurationParams { PathMappingSettings getMappingSettings(); void setMappingSettings(@Nullable PathMappingSettings mappingSettings); + + boolean addContentRoots(); + boolean addSourceRoots(); + void addContentRoots(boolean add); + void addSourceRoots(boolean add); } diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java new file mode 100644 index 000000000000..d13a0c9d1280 --- /dev/null +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaMethodType.java @@ -0,0 +1,69 @@ +package com.jetbrains.python.psi.impl; + +import com.intellij.psi.PsiMethod; +import com.intellij.util.ArrayUtil; +import com.intellij.util.ProcessingContext; +import com.jetbrains.python.psi.AccessDirection; +import com.jetbrains.python.psi.PyExpression; +import com.jetbrains.python.psi.PyQualifiedExpression; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import com.jetbrains.python.psi.resolve.RatedResolveResult; +import com.jetbrains.python.psi.types.PyCallableType; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.TypeEvalContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; + +/** + * @author yole + */ +public class PyJavaMethodType implements PyCallableType { + private final PsiMethod myMethod; + + public PyJavaMethodType(PsiMethod method) { + myMethod = method; + } + + @Override + public boolean isCallable() { + return true; + } + + @Nullable + @Override + public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { + return PyJavaTypeProvider.asPyType(myMethod.getReturnType()); + } + + @Nullable + @Override + public List resolveMember(@NotNull String name, + @Nullable PyExpression location, + AccessDirection direction, + PyResolveContext resolveContext) { + return Collections.emptyList(); + } + + @Override + public Object[] getCompletionVariants(String completionPrefix, PyExpression location, ProcessingContext context) { + return ArrayUtil.EMPTY_OBJECT_ARRAY; + } + + @Nullable + @Override + public String getName() { + return "Java method(" + myMethod.getContainingClass().getQualifiedName() + "." + myMethod.getName() + ")"; + } + + @Override + public boolean isBuiltin(TypeEvalContext context) { + return false; + } + + @Override + public void assertValid(String message) { + } +} diff --git a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java index 9d186f315c9e..5ecf0d86d2f6 100644 --- a/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java +++ b/python/pluginSrc/com/jetbrains/python/psi/impl/PyJavaTypeProvider.java @@ -30,7 +30,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase { } if (referenceTarget instanceof PsiMethod) { PsiMethod method = (PsiMethod) referenceTarget; - return asPyType(method.getReturnType()); + return new PyJavaMethodType(method); } if (referenceTarget instanceof PsiField) { return asPyType(((PsiField)referenceTarget).getType()); @@ -39,7 +39,7 @@ public class PyJavaTypeProvider extends PyTypeProviderBase { } @Nullable - private static PyType asPyType(PsiType type) { + public static PyType asPyType(PsiType type) { if (type instanceof PsiClassType) { final PsiClassType classType = (PsiClassType)type; final PsiClass psiClass = classType.resolve(); diff --git a/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.form b/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.form index b6710a79e6a9..bdf524618b39 100644 --- a/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.form +++ b/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.form @@ -2,12 +2,12 @@
- + - + @@ -113,6 +113,22 @@ + + + + + + + + + + + + + + + + diff --git a/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.java b/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.java index 4b29678cbcba..91a9249dee4a 100644 --- a/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.java +++ b/python/pluginSrc/com/jetbrains/python/run/PyPluginCommonOptionsForm.java @@ -1,8 +1,8 @@ package com.jetbrains.python.run; import com.intellij.execution.configuration.EnvironmentVariablesComponent; -import com.intellij.ide.util.PropertiesComponent; import com.intellij.execution.util.PathMappingsComponent; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; @@ -16,12 +16,12 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.ui.CollectionComboBoxModel; import com.intellij.ui.HideableDecorator; import com.intellij.ui.RawCommandLineEditor; +import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.JBLabel; import com.intellij.util.PathMappingSettings; import com.jetbrains.python.sdk.PreferredSdkComparator; import com.jetbrains.python.sdk.PySdkUtil; import com.jetbrains.python.sdk.PythonSdkType; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -50,6 +50,8 @@ public class PyPluginCommonOptionsForm implements AbstractPyCommonOptionsForm { private JBLabel myWorkingDirectoryJBLabel; private JPanel myHideablePanel; private PathMappingsComponent myPathMappingsComponent; + private JBCheckBox myAddContentRootsCheckbox; + private JBCheckBox myAddSourceRootsCheckbox; private JComponent labelAnchor; private final HideableDecorator myDecorator; @@ -235,4 +237,25 @@ public class PyPluginCommonOptionsForm implements AbstractPyCommonOptionsForm { myWorkingDirectoryJBLabel.setAnchor(anchor); myEnvsComponent.setAnchor(anchor); } + + @Override + public boolean addContentRoots() { + return myAddContentRootsCheckbox.isSelected(); + } + + @Override + public boolean addSourceRoots() { + return myAddSourceRootsCheckbox.isSelected(); + } + + @Override + public void addContentRoots(boolean add) { + myAddContentRootsCheckbox.setSelected(add); + } + + @Override + public void addSourceRoots(boolean add) { + myAddSourceRootsCheckbox.setSelected(add); + } + } diff --git a/python/pluginTestSrc/com/jetbrains/jython/PyJythonHighlightingTest.java b/python/pluginTestSrc/com/jetbrains/jython/PyJythonHighlightingTest.java index 8ddd01f29daf..b7a65df539bd 100644 --- a/python/pluginTestSrc/com/jetbrains/jython/PyJythonHighlightingTest.java +++ b/python/pluginTestSrc/com/jetbrains/jython/PyJythonHighlightingTest.java @@ -3,14 +3,23 @@ package com.jetbrains.jython; import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import com.jetbrains.python.PythonTestUtil; import com.jetbrains.python.inspections.PyCallingNonCallableInspection; +import com.jetbrains.python.inspections.PyUnresolvedReferencesInspection; /** * @author yole */ public class PyJythonHighlightingTest extends LightCodeInsightFixtureTestCase { public void testCallableJavaClass() { - myFixture.configureByFile("callableJavaClass.py"); - myFixture.enableInspections(PyCallingNonCallableInspection.class); + doCallableTest(); + } + + public void testCallableStaticMethod() { + doCallableTest(); + } + + private void doCallableTest() { + myFixture.configureByFile(getTestName(false) + ".py"); + myFixture.enableInspections(PyCallingNonCallableInspection.class, PyUnresolvedReferencesInspection.class); myFixture.checkHighlighting(true, false, false); } diff --git a/python/pydevSrc/com/jetbrains/python/console/pydev/AbstractConsoleCommunication.java b/python/pydevSrc/com/jetbrains/python/console/pydev/AbstractConsoleCommunication.java index 4d40f1e01810..fa832cff38d5 100644 --- a/python/pydevSrc/com/jetbrains/python/console/pydev/AbstractConsoleCommunication.java +++ b/python/pydevSrc/com/jetbrains/python/console/pydev/AbstractConsoleCommunication.java @@ -1,12 +1,11 @@ package com.jetbrains.python.console.pydev; -import com.google.common.collect.Lists; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; import java.util.List; -import java.util.Vector; /** * @author traff @@ -23,7 +22,7 @@ public abstract class AbstractConsoleCommunication implements ConsoleCommunicati */ public volatile boolean waitingForInput; - private List communicationListeners = Lists.newArrayList(); + private final List communicationListeners = ContainerUtil.createLockFreeCopyOnWriteList(); public AbstractConsoleCommunication(Project project) { diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 714cbeed3621..20f471f58c08 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -11,6 +11,7 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.xdebugger.frame.XValueChildrenList; import com.jetbrains.python.console.pydev.PydevCompletionVariant; import com.jetbrains.python.debugger.*; @@ -54,7 +55,7 @@ public class RemoteDebugger implements ProcessDebugger { private final TempVarsHolder myTempVars = new TempVarsHolder(); - private final List myCloseListeners = Lists.newArrayList(); + private final List myCloseListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private DebuggerReader myDebuggerReader; public RemoteDebugger(final IPyDebugProcess debugProcess, final ServerSocket serverSocket, final int timeout) { diff --git a/python/python-rest/src/com/jetbrains/rest/run/RestConfigurationEditor.form b/python/python-rest/src/com/jetbrains/rest/run/RestConfigurationEditor.form index 3bd513770d44..798c38ea8c3f 100644 --- a/python/python-rest/src/com/jetbrains/rest/run/RestConfigurationEditor.form +++ b/python/python-rest/src/com/jetbrains/rest/run/RestConfigurationEditor.form @@ -1,16 +1,16 @@ - + - + - + @@ -83,12 +83,6 @@ - - - - - - diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java index c419f521048f..f17eb83d68d0 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertFormatOperatorToMethodIntention.java @@ -202,6 +202,10 @@ public class ConvertFormatOperatorToMethodIntention extends BaseIntentionAction } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyBinaryExpression binaryExpression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class, false); if (binaryExpression == null) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java index 5a635aa57fef..436bdaf46c34 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ConvertVariadicParamIntention.java @@ -44,6 +44,10 @@ public class ConvertVariadicParamIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyFunction function = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyFunction.class); if (function != null) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java index bb881905c74b..509513ff32cc 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportFromToImportIntention.java @@ -128,6 +128,10 @@ public class ImportFromToImportIntention implements IntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + InfoHolder info = InfoHolder.collect(getElementFromEditor(editor, file)); info.myModuleReference = null; final PsiElement position = file.findElementAt(editor.getCaretModel().getOffset()); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java index 7a7767b6d8b8..ffaabaa1fd2f 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToImportFromIntention.java @@ -214,6 +214,10 @@ public class ImportToImportFromIntention implements IntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + IntentionState state = new IntentionState(editor, file); if (state.isAvailable()) { myText = state.getText(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java index 166206f6451b..335c37178a62 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ImportToggleAliasIntention.java @@ -103,6 +103,10 @@ public class ImportToggleAliasIntention implements IntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + IntentionState state = IntentionState.fromContext(editor, file); myLastText = state.getText(); return state.isAvailable(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java index 462b4d723f37..e9fe4b870465 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertLambdaToFunctionIntention.java @@ -40,6 +40,10 @@ public class PyConvertLambdaToFunctionIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyLambdaExpression.class); if (lambdaExpression != null) { if (lambdaExpression.getBody() != null) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertTripleQuotedStringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertTripleQuotedStringIntention.java index a84d19f71dd7..dd420026e520 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertTripleQuotedStringIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyConvertTripleQuotedStringIntention.java @@ -42,6 +42,10 @@ public class PyConvertTripleQuotedStringIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyStringLiteralExpression string = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyStringLiteralExpression.class); if (string != null) { final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(string, PyDocStringOwner.class); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDemorganIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDemorganIntention.java index 64271ef3366f..4becd23721ce 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDemorganIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDemorganIntention.java @@ -30,6 +30,10 @@ public class PyDemorganIntention extends BaseIntentionAction { @Override public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyBinaryExpression expression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class); if (expression != null) { PyElementType op = expression.getOperator(); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java index 34634a3e03f3..c25580b1fd8d 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictConstructorToLiteralFormIntention.java @@ -33,6 +33,10 @@ public class PyDictConstructorToLiteralFormIntention extends BaseIntentionAction } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyCallExpression expression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyCallExpression.class); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictLiteralFormToConstructorIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictLiteralFormToConstructorIntention.java index a87ed6eb6c21..2a36bc9ca5da 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyDictLiteralFormToConstructorIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyDictLiteralFormToConstructorIntention.java @@ -33,6 +33,9 @@ public class PyDictLiteralFormToConstructorIntention extends BaseIntentionAction } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } PyDictLiteralExpression dictExpression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyDictLiteralExpression.class); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyFlipComparisonIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyFlipComparisonIntention.java index 3e6be16fd645..84ec2d5b0b6e 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyFlipComparisonIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyFlipComparisonIntention.java @@ -13,6 +13,7 @@ import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.psi.PyBinaryExpression; import com.jetbrains.python.psi.PyElementGenerator; import com.jetbrains.python.psi.PyElementType; +import com.jetbrains.python.psi.PyFile; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -42,6 +43,10 @@ public class PyFlipComparisonIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); PyBinaryExpression binaryExpression = PsiTreeUtil.getParentOfType(element, PyBinaryExpression.class, false); while (binaryExpression != null) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java index 1f53df064d86..1940d7cc233c 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyGenerateDocstringIntention.java @@ -13,6 +13,7 @@ import com.jetbrains.python.debugger.PySignature; import com.jetbrains.python.debugger.PySignatureCacheManager; import com.jetbrains.python.documentation.PyDocstringGenerator; import com.jetbrains.python.documentation.doctest.PyDocstringFile; +import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyFunction; import com.jetbrains.python.psi.PyUtil; import org.jetbrains.annotations.NotNull; @@ -37,7 +38,7 @@ public class PyGenerateDocstringIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - if (file instanceof PyDocstringFile) return false; + if (!(file instanceof PyFile) || file instanceof PyDocstringFile) return false; PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset()); if (elementAt == null) { return false; diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java index 3ee654506755..7421520190d3 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyJoinIfIntention.java @@ -39,6 +39,10 @@ public class PyJoinIfIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyIfStatement expression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyIfStatement.class); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyNegateComparisonIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyNegateComparisonIntention.java index 788915d1be38..cedf015dc498 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyNegateComparisonIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyNegateComparisonIntention.java @@ -49,6 +49,9 @@ public class PyNegateComparisonIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); PyBinaryExpression binaryExpression = PsiTreeUtil.getParentOfType(element, PyBinaryExpression.class, false); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyQuotedStringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyQuotedStringIntention.java index c73e3216038b..95cf10332609 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyQuotedStringIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyQuotedStringIntention.java @@ -9,6 +9,7 @@ import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.PyDocStringOwner; import com.jetbrains.python.psi.PyElementGenerator; +import com.jetbrains.python.psi.PyFile; import com.jetbrains.python.psi.PyStringLiteralExpression; import com.jetbrains.python.psi.impl.PyStringLiteralExpressionImpl; import org.jetbrains.annotations.NotNull; @@ -25,6 +26,10 @@ public class PyQuotedStringIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyStringLiteralExpression string = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyStringLiteralExpression.class); if (string != null) { final PyDocStringOwner docStringOwner = PsiTreeUtil.getParentOfType(string, PyDocStringOwner.class); diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PySplitIfIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PySplitIfIntention.java index aaf3254e7379..20a77cb070de 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PySplitIfIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PySplitIfIntention.java @@ -26,6 +26,10 @@ public class PySplitIfIntention extends BaseIntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PsiElement elementAtOffset = file.findElementAt(editor.getCaretModel().getOffset()); if (elementAtOffset == null || elementAtOffset.getNode() == null) { return false; diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java index 690207bcb9f5..aadbaa1897ef 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java @@ -35,6 +35,10 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PsiElement element = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class, false); if (element == null) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyTransformConditionalExpressionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyTransformConditionalExpressionIntention.java index 93e770441e5d..e98eb03c316b 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyTransformConditionalExpressionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyTransformConditionalExpressionIntention.java @@ -36,6 +36,10 @@ public class PyTransformConditionalExpressionIntention extends BaseIntentionActi } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyAssignmentStatement expression = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyAssignmentStatement.class); if (expression != null && expression.getAssignedValue() instanceof PyConditionalExpression) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/ReplaceListComprehensionWithForIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/ReplaceListComprehensionWithForIntention.java index 6154b79bca44..9beb2a40fe39 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/ReplaceListComprehensionWithForIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/ReplaceListComprehensionWithForIntention.java @@ -29,6 +29,10 @@ public class ReplaceListComprehensionWithForIntention implements IntentionAction } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PyListCompExpression expression = PsiTreeUtil.getTopmostParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyListCompExpression.class); if (expression == null) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInPy3AnnotationsIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInPy3AnnotationsIntention.java index 00976042431b..cdb93416f71e 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInPy3AnnotationsIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInPy3AnnotationsIntention.java @@ -71,16 +71,17 @@ public class SpecifyTypeInPy3AnnotationsIntention extends TypeIntention { parameter = (PyParameter)parameter.replace(namedParameter); parameter = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(parameter); editor.getCaretModel().moveToOffset(parameter.getTextOffset()); - PyAnnotation annotation = namedParameter.getAnnotation(); - assert annotation != null; - PyExpression annotationValue = annotation.getValue(); + PyAnnotation annotation = parameter instanceof PyNamedParameter? ((PyNamedParameter)parameter).getAnnotation() : null; + if (annotation != null) { + PyExpression annotationValue = annotation.getValue(); - final TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(parameter); - int replacementStart = annotation.getStartOffsetInParent() + annotationValue.getStartOffsetInParent(); - builder.replaceRange(TextRange.create(replacementStart, - replacementStart + annotationValue.getTextLength()), PyNames.OBJECT); - Template template = ((TemplateBuilderImpl)builder).buildInlineTemplate(); - TemplateManager.getInstance(project).startTemplate(editor, template); + final TemplateBuilder builder = TemplateBuilderFactory.getInstance().createTemplateBuilder(parameter); + int replacementStart = annotation.getStartOffsetInParent() + annotationValue.getStartOffsetInParent(); + builder.replaceRange(TextRange.create(replacementStart, + replacementStart + annotationValue.getTextLength()), PyNames.OBJECT); + Template template = ((TemplateBuilderImpl)builder).buildInlineTemplate(); + TemplateManager.getInstance(project).startTemplate(editor, template); + } } private void annotateReturnType(Project project, PsiElement resolved) { diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java index 1dc1d8ca8309..e3cea61295bd 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/TypeAssertionIntention.java @@ -41,6 +41,10 @@ public class TypeAssertionIntention implements IntentionAction { } public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + if (!(file instanceof PyFile)) { + return false; + } + PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset()); PyExpression problemElement = PsiTreeUtil.getParentOfType(elementAt, PyReferenceExpression.class); if (problemElement == null) return false; diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/TypeIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/TypeIntention.java index 5777e44ee12e..37c309997b4d 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/TypeIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/TypeIntention.java @@ -24,7 +24,7 @@ import org.jetbrains.annotations.Nullable; public abstract class TypeIntention implements IntentionAction { public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { - if (file instanceof PyDocstringFile) return false; + if (!(file instanceof PyFile) || file instanceof PyDocstringFile) return false; updateText(false); final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset()); diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java index 2c824e67048d..858ea2712712 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyNamedTupleType.java @@ -25,16 +25,20 @@ import java.util.List; */ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType { private final String myName; - private final boolean myDefinition; + + // 2 - namedtuple call itself + // 1 - return type of namedtuple call, aka namedtuple class + // 0 - namedtuple instance + private final int myDefinitionLevel; private final PsiElement myDeclaration; private final List myFields; - public PyNamedTupleType(PyClass tupleClass, PsiElement declaration, String name, List fields, boolean isDefinition) { - super(tupleClass, isDefinition); + public PyNamedTupleType(PyClass tupleClass, PsiElement declaration, String name, List fields, int definitionLevel) { + super(tupleClass, definitionLevel > 0); myDeclaration = declaration; myFields = fields; myName = name; - myDefinition = isDefinition; + myDefinitionLevel = definitionLevel; } @Override @@ -75,15 +79,15 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType @Nullable @Override public PyType getCallType(@NotNull TypeEvalContext context, @Nullable PyQualifiedExpression callSite) { - if (myDefinition) { - return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, false); + if (myDefinitionLevel > 0) { + return new PyNamedTupleType(myClass, myDeclaration, myName, myFields, myDefinitionLevel-1); } return null; } @Override public PyClassType toInstance() { - return myIsDefinition ? new PyNamedTupleType(myClass, myDeclaration, myName, myFields, false) : this; + return myDefinitionLevel == 1 ? new PyNamedTupleType(myClass, myDeclaration, myName, myFields, 0) : this; } @Override @@ -92,7 +96,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType } @Nullable - public static PyType fromCall(PyCallExpression call) { + public static PyType fromCall(PyCallExpression call, int level) { final String name = PyPsiUtils.strValue(call.getArgument(0, PyExpression.class)); final PyExpression fieldNamesExpression = PyPsiUtils.flattenParens(call.getArgument(1, PyExpression.class)); if (name == null || fieldNamesExpression == null) { @@ -111,7 +115,7 @@ public class PyNamedTupleType extends PyClassTypeImpl implements PyCallableType if (fieldNames != null) { PyClass tuple = PyBuiltinCache.getInstance(call).getClass(PyNames.FAKE_NAMEDTUPLE); if (tuple != null) { - return new PyNamedTupleType(tuple, call, name, fieldNames, true); + return new PyNamedTupleType(tuple, call, name, fieldNames, level); } } return null; diff --git a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java index 9802764908e4..dcceff5271c7 100644 --- a/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java +++ b/python/src/com/jetbrains/python/codeInsight/stdlib/PyStdlibTypeProvider.java @@ -58,7 +58,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { if (callee != null) { final Callable callable = callee.getCallable(); if (PyNames.COLLECTIONS_PY.equals(callable.getContainingFile().getName())) { - return PyNamedTupleType.fromCall(call); + return PyNamedTupleType.fromCall(call, 1); } } } @@ -67,7 +67,7 @@ public class PyStdlibTypeProvider extends PyTypeProviderBase { else if (referenceTarget instanceof PyFunction && anchor instanceof PyCallExpression) { if (PyNames.NAMEDTUPLE.equals(((PyFunction)referenceTarget).getName()) && PyNames.COLLECTIONS_PY.equals(referenceTarget.getContainingFile().getName())) { - return PyNamedTupleType.fromCall((PyCallExpression)anchor); + return PyNamedTupleType.fromCall((PyCallExpression)anchor, 2); } } return null; diff --git a/python/src/com/jetbrains/python/console/PyConsoleOptionsProvider.java b/python/src/com/jetbrains/python/console/PyConsoleOptionsProvider.java index 9968c6f042f0..76d39e7410c5 100644 --- a/python/src/com/jetbrains/python/console/PyConsoleOptionsProvider.java +++ b/python/src/com/jetbrains/python/console/PyConsoleOptionsProvider.java @@ -96,6 +96,9 @@ public class PyConsoleOptionsProvider implements PersistentStateComponent myEnvs = Maps.newHashMap(); public String myWorkingDirectory = ""; + public boolean myAddContentRoots = true; + public boolean myAddSourceRoots; + @Transient private Project myProject; @@ -114,13 +117,18 @@ public class PyConsoleOptionsProvider implements PersistentStateComponent getEnvs() { return myEnvs; } + + public boolean addContentRoots() { + return myAddContentRoots; + } + + public boolean addSourceRoots() { + return myAddSourceRoots; + } + } } diff --git a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java index 4ddbb6ce2e16..b9591b6aabdb 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleRunner.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleRunner.java @@ -41,6 +41,7 @@ import com.intellij.psi.impl.source.tree.FileElement; import com.intellij.testFramework.LightVirtualFile; import com.intellij.util.ArrayUtil; import com.intellij.util.IJSwingUtilities; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.net.NetUtils; import com.intellij.util.ui.UIUtil; import com.jetbrains.django.run.ProcessRunner; @@ -82,7 +83,7 @@ public class PydevConsoleRunner extends AbstractConsoleRunnerWithHistory myConsoleListeners = Lists.newArrayList(); + private List myConsoleListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private final PyConsoleType myConsoleType; private Map myEnvironmentVariables; private String myCommandLine; diff --git a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java index 6040041ed20a..5ccebbd37169 100644 --- a/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java +++ b/python/src/com/jetbrains/python/console/RunPythonConsoleAction.java @@ -65,12 +65,12 @@ public class RunPythonConsoleAction extends AnAction implements DumbAware { String[] setup_fragment; - Collection pythonPath = PythonCommandLineState.collectPythonPath(module); + PyConsoleOptionsProvider.PyConsoleSettings settingsProvider = PyConsoleOptionsProvider.getInstance(project).getPythonConsoleSettings(); + Collection pythonPath = PythonCommandLineState.collectPythonPath(module, settingsProvider.addContentRoots(), + settingsProvider.addSourceRoots()); String self_path_append = constructPythonPathCommand(pythonPath); - PyConsoleOptionsProvider.PyConsoleSettings settingsProvider = PyConsoleOptionsProvider.getInstance(project).getPythonConsoleSettings(); - String customStartScript = settingsProvider.getCustomStartScript(); if (customStartScript.trim().length() > 0) { diff --git a/python/src/com/jetbrains/python/module/PythonModuleBuilderBase.java b/python/src/com/jetbrains/python/module/PythonModuleBuilderBase.java index 58490f68fc9f..2cd9fa47a3c3 100644 --- a/python/src/com/jetbrains/python/module/PythonModuleBuilderBase.java +++ b/python/src/com/jetbrains/python/module/PythonModuleBuilderBase.java @@ -12,19 +12,19 @@ import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.platform.DirectoryProjectGenerator; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.PythonModuleTypeBase; import com.jetbrains.python.sdk.PythonSdkType; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; /** * @author yole */ public class PythonModuleBuilderBase extends ModuleBuilder { - private final List mySdkChangedListeners = new ArrayList(); + private final List mySdkChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private final DirectoryProjectGenerator myGenerator; private Sdk mySdk; diff --git a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java index 4122f513e4d2..a5c11168e5d2 100644 --- a/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java +++ b/python/src/com/jetbrains/python/packaging/PyPIPackageUtil.java @@ -7,6 +7,7 @@ import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.Messages; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.components.JBLabel; +import com.intellij.util.net.HttpConfigurable; import org.apache.xmlrpc.*; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -23,10 +24,7 @@ import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.parser.ParserDelegator; import java.awt.*; import java.io.*; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLDecoder; +import java.net.*; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -216,7 +214,6 @@ public class PyPIPackageUtil { } }; - URL repositoryUrl = new URL(PYPI_LIST_URL); // Create a trust manager that does not validate certificate TrustManager[] trustAllCerts = new TrustManager[]{new PyPITrustManager()}; @@ -225,7 +222,9 @@ public class PyPIPackageUtil { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new SecureRandom()); - final URLConnection connection = repositoryUrl.openConnection(); + final HttpConfigurable settings = HttpConfigurable.getInstance(); + final URLConnection connection = settings.openConnection(PYPI_LIST_URL); + if (connection instanceof HttpsURLConnection) { ((HttpsURLConnection)connection).setSSLSocketFactory(sslContext.getSocketFactory()); } @@ -307,7 +306,8 @@ public class PyPIPackageUtil { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, trustAllCerts, new SecureRandom()); - con = url.openConnection(); + final HttpConfigurable settings = HttpConfigurable.getInstance(); + con = settings.openConnection(PYPI_LIST_URL); if (con instanceof HttpsURLConnection) { ((HttpsURLConnection)con).setSSLSocketFactory(sslContext.getSocketFactory()); } diff --git a/python/src/com/jetbrains/python/packaging/ui/PyPackagesPanel.java b/python/src/com/jetbrains/python/packaging/ui/PyPackagesPanel.java index 6abbed6f2231..2b5b4156a2f1 100644 --- a/python/src/com/jetbrains/python/packaging/ui/PyPackagesPanel.java +++ b/python/src/com/jetbrains/python/packaging/ui/PyPackagesPanel.java @@ -13,6 +13,7 @@ import com.intellij.ui.DoubleClickListener; import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.table.JBTable; import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; import com.jetbrains.python.packaging.*; import com.jetbrains.python.sdk.flavors.IronPythonSdkFlavor; import com.jetbrains.python.sdk.flavors.PythonSdkFlavor; @@ -52,7 +53,7 @@ public class PyPackagesPanel extends JPanel { private final PyPackagesNotificationPanel myNotificationArea; private boolean myHasDistribute; private boolean myHasPip = true; - private final List> myPathChangedListeners = new ArrayList>(); + private final List> myPathChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList(); private Set currentlyInstalling = new HashSet(); public PyPackagesPanel(Project project, PyPackagesNotificationPanel area) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java index fee8f42449c1..844a41a1576a 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java +++ b/python/src/com/jetbrains/python/psi/impl/PyCallExpressionHelper.java @@ -419,8 +419,8 @@ public class PyCallExpressionHelper { return new PyClassTypeImpl(cls, false); } final PyType providedType = PyReferenceExpressionImpl.getReferenceTypeFromProviders(target, context, call); - if (providedType != null) { - return providedType; + if (providedType instanceof PyCallableType) { + return ((PyCallableType) providedType).getCallType(context, (PyReferenceExpression)callee); } if (target instanceof Callable) { final Callable callable = (Callable)target; diff --git a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java index eec1e18cbde4..d7249521648b 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyElementGeneratorImpl.java @@ -254,7 +254,7 @@ public class PyElementGeneratorImpl extends PyElementGenerator { @NotNull LanguageLevel languageLevel) { String parameterText = name; if (annotation != null) - parameterText += " : " + annotation; + parameterText += ": " + annotation; if (defaultValue != null) parameterText += " = " + defaultValue; diff --git a/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java b/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java index 979decedb251..fc1d6db3e244 100644 --- a/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java +++ b/python/src/com/jetbrains/python/run/AbstractPythonRunConfiguration.java @@ -39,6 +39,8 @@ public abstract class AbstractPythonRunConfiguration(source.getEnvs())); target.setInterpreterOptions(source.getInterpreterOptions()); @@ -275,6 +301,8 @@ public abstract class AbstractPythonRunConfiguration collectPythonPath() { final Module module = myConfig.getModule(); - Set pythonPath = Sets.newHashSet(collectPythonPath(module)); + Set pythonPath = Sets.newHashSet(collectPythonPath(module, myConfig.addContentRoots(), myConfig.addSourceRoots())); if (isDebug() && getSdkFlavor() instanceof JythonSdkFlavor) { //that fixes Jython problem changing sys.argv on execfile, see PY-8164 pythonPath.add(PythonHelpersLocator.getHelperPath("pycharm")); @@ -343,18 +346,34 @@ public abstract class PythonCommandLineState extends CommandLineState { @NotNull public static Collection collectPythonPath(@Nullable Module module) { - return collectPythonPath(module, true); + return collectPythonPath(module, true, true); } @NotNull - public static Collection collectPythonPath(@Nullable Module module, final boolean addProjectRoots) { + public static Collection collectPythonPath(@Nullable Module module, boolean addContentRoots, + boolean addSourceRoots) { Collection pythonPathList = Sets.newLinkedHashSet(); - if (module != null && addProjectRoots) { - addLibrariesFromModule(module, pythonPathList); + if (module != null) { Set dependencies = new HashSet(); ModuleUtil.getDependencies(module, dependencies); + + if (addContentRoots) { + addRoots(pythonPathList, ModuleRootManager.getInstance(module).getContentRoots()); + for (Module dependency : dependencies) { + addRoots(pythonPathList, ModuleRootManager.getInstance(dependency).getContentRoots()); + } + } + if (addSourceRoots) { + addRoots(pythonPathList, ModuleRootManager.getInstance(module).getSourceRoots()); + for (Module dependency : dependencies) { + addRoots(pythonPathList, ModuleRootManager.getInstance(dependency).getSourceRoots()); + } + } + + addLibrariesFromModule(module, pythonPathList); + addRootsFromModule(module, pythonPathList); for (Module dependency : dependencies) { - addLibrariesFromModule(module, pythonPathList); + addLibrariesFromModule(dependency, pythonPathList); addRootsFromModule(dependency, pythonPathList); } } @@ -378,10 +397,8 @@ public abstract class PythonCommandLineState extends CommandLineState { } private static void addRootsFromModule(Module module, Collection pythonPathList) { - final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - addRoots(pythonPathList, moduleRootManager.getContentRoots()); - addRoots(pythonPathList, moduleRootManager.getSourceRoots()); + // for Jython final CompilerModuleExtension extension = CompilerModuleExtension.getInstance(module); if (extension != null) { final VirtualFile path = extension.getCompilerOutputPath(); @@ -394,6 +411,7 @@ public abstract class PythonCommandLineState extends CommandLineState { } } + //additional paths from facets (f.e. buildout) final Facet[] facets = FacetManager.getInstance(module).getAllFacets(); for (Facet facet : facets) { if (facet instanceof PythonPathContributingFacet) { diff --git a/python/src/com/jetbrains/python/run/PythonTask.java b/python/src/com/jetbrains/python/run/PythonTask.java index 767ecf92629c..d0bf589eac4c 100644 --- a/python/src/com/jetbrains/python/run/PythonTask.java +++ b/python/src/com/jetbrains/python/run/PythonTask.java @@ -148,14 +148,12 @@ public class PythonTask { } protected List setupPythonPath() { - return setupPythonPath(true); + return setupPythonPath(true, true); } - protected List setupPythonPath(final boolean addProjectRoot) { + protected List setupPythonPath(final boolean addContent, final boolean addSource) { final List pythonPath = Lists.newArrayList(PythonCommandLineState.getAddedPaths(mySdk)); - if (addProjectRoot) { - pythonPath.addAll(PythonCommandLineState.collectPythonPath(myModule)); - } + pythonPath.addAll(PythonCommandLineState.collectPythonPath(myModule, addContent, addSource)); return pythonPath; } diff --git a/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.java b/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.java index 7b327e7ce78a..cd43a0516519 100644 --- a/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.java +++ b/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfiguration.java @@ -41,6 +41,8 @@ public abstract class AbstractPythonTestRunConfiguration extends AbstractPythonR private String myPattern = ""; // pattern for modules in folder to match against private boolean usePattern = false; + protected boolean myAddContentRoots = false; + protected boolean myAddSourceRoots = false; protected AbstractPythonTestRunConfiguration(RunConfigurationModule module, ConfigurationFactory configurationFactory, String name) { super(name, module, configurationFactory); @@ -56,6 +58,8 @@ public abstract class AbstractPythonTestRunConfiguration extends AbstractPythonR myPattern = JDOMExternalizerUtil.readField(element, "PATTERN"); usePattern = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, "USE_PATTERN")); + myAddContentRoots = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, "ADD_CONTENT_ROOTS")); + myAddSourceRoots = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, "ADD_SOURCE_ROOTS")); try { final String testType = JDOMExternalizerUtil.readField(element, "TEST_TYPE"); @@ -77,6 +81,8 @@ public abstract class AbstractPythonTestRunConfiguration extends AbstractPythonR JDOMExternalizerUtil.writeField(element, "TEST_TYPE", myTestType.toString()); JDOMExternalizerUtil.writeField(element, "PATTERN", myPattern); JDOMExternalizerUtil.writeField(element, "USE_PATTERN", String.valueOf(usePattern)); + JDOMExternalizerUtil.writeField(element, "ADD_CONTENT_ROOTS", String.valueOf(myAddContentRoots)); + JDOMExternalizerUtil.writeField(element, "ADD_SOURCE_ROOTS", String.valueOf(myAddSourceRoots)); } public AbstractPythonRunConfigurationParams getBaseParams() { @@ -204,6 +210,8 @@ public abstract class AbstractPythonTestRunConfiguration extends AbstractPythonR target.setTestType(source.getTestType()); target.setPattern(source.getPattern()); target.usePattern(source.usePattern()); + target.addContentRoots(source.addContentRoots()); + target.addSourceRoots(source.addSourceRoots()); } public AbstractPythonTestRunConfigurationParams getTestRunConfigurationParams() { @@ -339,4 +347,24 @@ public abstract class AbstractPythonTestRunConfiguration extends AbstractPythonR private static boolean pathsEqual(VirtualFile vFile, final String folderName) { return Comparing.equal(new File(vFile.getPath()).getAbsolutePath(), new File(folderName).getAbsolutePath()); } + + @Override + public boolean addSourceRoots() { + return myAddSourceRoots; + } + + @Override + public boolean addContentRoots() { + return myAddContentRoots; + } + + @Override + public void addSourceRoots(boolean addSourceRoots) { + myAddSourceRoots = addSourceRoots; + } + + @Override + public void addContentRoots(boolean addContentRoots) { + myAddContentRoots = addContentRoots; + } } diff --git a/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfigurationParams.java b/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfigurationParams.java index 7e09611dffb2..0ce3c6d8736e 100644 --- a/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfigurationParams.java +++ b/python/src/com/jetbrains/python/testing/AbstractPythonTestRunConfigurationParams.java @@ -28,4 +28,9 @@ public interface AbstractPythonTestRunConfigurationParams { String getPattern(); void setPattern(String pattern); + + boolean addContentRoots(); + boolean addSourceRoots(); + void addContentRoots(boolean addContentRoots); + void addSourceRoots(boolean addSourceRoots); } diff --git a/python/src/com/jetbrains/python/testing/PythonTestRunConfigurationForm.java b/python/src/com/jetbrains/python/testing/PythonTestRunConfigurationForm.java index 23dab2c36adb..f71a65787220 100644 --- a/python/src/com/jetbrains/python/testing/PythonTestRunConfigurationForm.java +++ b/python/src/com/jetbrains/python/testing/PythonTestRunConfigurationForm.java @@ -123,6 +123,26 @@ public class PythonTestRunConfigurationForm implements AbstractPythonTestRunConf myPatternTextField.setText(pattern); } + @Override + public boolean addContentRoots() { + return myCommonOptionsForm.addContentRoots(); + } + + @Override + public boolean addSourceRoots() { + return myCommonOptionsForm.addSourceRoots(); + } + + @Override + public void addContentRoots(boolean addContentRoots) { + myCommonOptionsForm.addContentRoots(addContentRoots); + } + + @Override + public void addSourceRoots(boolean addSourceRoots) { + myCommonOptionsForm.addSourceRoots(addSourceRoots); + } + public String getFolderName() { return toSystemIndependentName(myTestFolderTextField.getText().trim()); } diff --git a/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java b/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java index 83c16743d335..2574fd5a71aa 100644 --- a/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java @@ -3,9 +3,7 @@ package com.jetbrains.python.testing.attest; import com.intellij.execution.runners.ExecutionEnvironment; import com.jetbrains.python.testing.PythonTestCommandLineStateBase; -import java.io.File; import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** @@ -25,19 +23,6 @@ public class PythonAtTestCommandLineState extends PythonTestCommandLineStateBase return UTRUNNER_PY; } - @Override - protected Collection collectPythonPath() { - List pythonPath = new ArrayList(super.collectPythonPath()); - // the first entry is the helpers path; add script directory as second entry - if (myConfig.getTestType() == PythonAtTestRunConfiguration.TestType.TEST_FOLDER) { - pythonPath.add(1, myConfig.getFolderName()); - } - else { - pythonPath.add(1, new File(myConfig.getScriptName()).getParent()); - } - return pythonPath; - } - protected List getTestSpecs() { List specs = new ArrayList(); diff --git a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestCommandLineState.java b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestCommandLineState.java index 9425492edf42..93f2fe87cdff 100644 --- a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestCommandLineState.java @@ -3,9 +3,7 @@ package com.jetbrains.python.testing.doctest; import com.intellij.execution.runners.ExecutionEnvironment; import com.jetbrains.python.testing.PythonTestCommandLineStateBase; -import java.io.File; import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** @@ -25,19 +23,6 @@ public class PythonDocTestCommandLineState extends PythonTestCommandLineStateBas return UTRUNNER_PY; } - @Override - protected Collection collectPythonPath() { - List pythonPath = new ArrayList(super.collectPythonPath()); - // the first entry is the helpers path; add script directory as second entry - if (myConfig.getTestType() == PythonDocTestRunConfiguration.TestType.TEST_FOLDER) { - pythonPath.add(1, myConfig.getFolderName()); - } - else { - pythonPath.add(1, new File(myConfig.getScriptName()).getParent()); - } - return pythonPath; - } - protected List getTestSpecs() { List specs = new ArrayList(); diff --git a/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java b/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java index e732bad1db9e..4f9d58a3dc4c 100644 --- a/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java @@ -7,13 +7,9 @@ import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.openapi.util.text.StringUtil; import com.jetbrains.python.testing.PythonTestCommandLineStateBase; -import java.io.File; import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import static com.jetbrains.python.testing.AbstractPythonTestRunConfiguration.TestType.TEST_FOLDER; - /** * @author Leonid Shalupov */ @@ -32,19 +28,6 @@ public class PythonUnitTestCommandLineState extends return UTRUNNER_PY; } - @Override - protected Collection collectPythonPath() { - List pythonPath = new ArrayList(super.collectPythonPath()); - // the first entry is the helpers path; add script directory as second entry - if (myConfig.getTestType() == TEST_FOLDER) { - pythonPath.add(1, myConfig.getFolderName()); - } - else { - pythonPath.add(1, new File(myConfig.getScriptName()).getParent()); - } - return pythonPath; - } - protected List getTestSpecs() { List specs = new ArrayList(); diff --git a/python/testData/highlighting/jython/callableStaticMethod.py b/python/testData/highlighting/jython/callableStaticMethod.py new file mode 100644 index 000000000000..59ff5a8945f7 --- /dev/null +++ b/python/testData/highlighting/jython/callableStaticMethod.py @@ -0,0 +1,4 @@ +from java.util import Collections + +x = Collections.emptyList() +s = x.size() diff --git a/python/testData/intentions/afterTypeAnnotation3.py b/python/testData/intentions/afterTypeAnnotation3.py index d0c49d419746..054f2a6a231f 100644 --- a/python/testData/intentions/afterTypeAnnotation3.py +++ b/python/testData/intentions/afterTypeAnnotation3.py @@ -1,2 +1,2 @@ -def g(x : object=None ): +def g(x: object=None): return x diff --git a/python/testData/intentions/afterTypeInPy3Annotation.py b/python/testData/intentions/afterTypeInPy3Annotation.py index 3dca05f293e4..53a85344911b 100644 --- a/python/testData/intentions/afterTypeInPy3Annotation.py +++ b/python/testData/intentions/afterTypeInPy3Annotation.py @@ -1,3 +1,3 @@ -def foo(a : object, b): +def foo(a: object, b): a. b = 1 \ No newline at end of file diff --git a/python/testData/testRunner/doctests/test_empty.py b/python/testData/testRunner/doctests/test_empty.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/python/testSrc/com/jetbrains/python/testRunner/PyDocTestRunnerTest.java b/python/testSrc/com/jetbrains/python/testRunner/PyDocTestRunnerTest.java index 295c683db446..15a73a646e88 100644 --- a/python/testSrc/com/jetbrains/python/testRunner/PyDocTestRunnerTest.java +++ b/python/testSrc/com/jetbrains/python/testRunner/PyDocTestRunnerTest.java @@ -25,7 +25,9 @@ public class PyDocTestRunnerTest extends LightPlatformTestCase { } public void testEmptySuite() throws ExecutionException { - String[] result = runUTRunner(PathManager.getHomePath()); + final File testDir = getTestDataDir(); + File testFile = new File(testDir, "test_empty.py"); + String[] result = runUTRunner(testDir.getPath(), testFile.getPath()); assertEquals("##teamcity[enteredTheMatrix]", result [0]); assertEquals("##teamcity[testCount count='0']", result [1]); }