Merge remote-tracking branch 'origin/master'

This commit is contained in:
Dmitry Trofimov
2013-03-05 18:27:20 +01:00
64 changed files with 804 additions and 453 deletions
+118 -109
View File
@@ -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))
+8 -6
View File
@@ -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)
+16 -11
View File
@@ -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()
+18 -9
View File
@@ -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)
+161 -155
View File
@@ -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 = '<doctest %s[%d]>' % (test.name, examplenum)
filename = '<doctest %s[%d]>' % (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())
+9 -2
View File
@@ -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
@@ -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)
+7 -4
View File
@@ -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:
+24 -31
View File
@@ -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)
TeamcityTestRunner().run(all, **options)
@@ -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);
}
@@ -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<? extends RatedResolveResult> 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) {
}
}
@@ -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();
@@ -2,12 +2,12 @@
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.run.PyPluginCommonOptionsForm">
<grid id="42d7b" binding="myHideablePanel" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<xy x="20" y="20" width="457" height="262"/>
<xy x="20" y="20" width="457" height="297"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="7" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="9" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints border-constraint="Center"/>
<properties/>
@@ -113,6 +113,22 @@
<text value="Path mappings"/>
</properties>
</component>
<component id="d919b" class="com.intellij.ui.components.JBCheckBox" binding="myAddContentRootsCheckbox">
<constraints>
<grid row="7" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Add content roots to PYTHONPATH"/>
</properties>
</component>
<component id="1c6cd" class="com.intellij.ui.components.JBCheckBox" binding="myAddSourceRootsCheckbox">
<constraints>
<grid row="8" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Add source roots to PYTHONPATH"/>
</properties>
</component>
</children>
</grid>
</children>
@@ -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);
}
}
@@ -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);
}
@@ -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<ConsoleCommunicationListener> communicationListeners = Lists.newArrayList();
private final List<ConsoleCommunicationListener> communicationListeners = ContainerUtil.createLockFreeCopyOnWriteList();
public AbstractConsoleCommunication(Project project) {
@@ -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<RemoteDebuggerCloseListener> myCloseListeners = Lists.newArrayList();
private final List<RemoteDebuggerCloseListener> myCloseListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private DebuggerReader myDebuggerReader;
public RemoteDebugger(final IPyDebugProcess debugProcess, final ServerSocket serverSocket, final int timeout) {
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.rest.run.RestConfigurationEditor">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="8" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="7" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="214" width="495" height="228"/>
<xy x="20" y="214" width="495" height="217"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<grid id="f4532" binding="myCommonOptionsPlaceholder" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="7" column="1" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
<grid row="6" column="1" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
@@ -83,12 +83,6 @@
<text resource-bundle="com/jetbrains/rest/RestBundle" key="runcfg.docutils.command"/>
</properties>
</component>
<component id="693f8" class="javax.swing.JSeparator">
<constraints>
<grid row="6" column="1" row-span="1" col-span="2" vsize-policy="7" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<hspacer id="93e6">
<constraints>
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false">
@@ -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) {
@@ -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) {
@@ -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());
@@ -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();
@@ -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();
@@ -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) {
@@ -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);
@@ -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();
@@ -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);
@@ -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);
@@ -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) {
@@ -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;
@@ -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);
@@ -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);
@@ -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);
@@ -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;
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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;
@@ -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());
@@ -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<String> myFields;
public PyNamedTupleType(PyClass tupleClass, PsiElement declaration, String name, List<String> fields, boolean isDefinition) {
super(tupleClass, isDefinition);
public PyNamedTupleType(PyClass tupleClass, PsiElement declaration, String name, List<String> 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;
@@ -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;
@@ -96,6 +96,9 @@ public class PyConsoleOptionsProvider implements PersistentStateComponent<PyCons
public String myModuleName = null;
public Map<String, String> 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<PyCons
myUseModuleSdk = form.isUseModuleSdk();
myModuleName = form.getModule() == null ? null : form.getModule().getName();
myWorkingDirectory = form.getWorkingDirectory();
myAddContentRoots = form.addContentRoots();
myAddSourceRoots = form.addSourceRoots();
}
public boolean isModified(AbstractPyCommonOptionsForm form) {
return !ComparatorUtil.equalsNullable(mySdkHome, form.getSdkHome()) ||
!myInterpreterOptions.equals(form.getInterpreterOptions()) ||
!myEnvs.equals(form.getEnvs()) ||
myUseModuleSdk != form.isUseModuleSdk()
myUseModuleSdk != form.isUseModuleSdk() ||
myAddContentRoots != form.addContentRoots() ||
myAddSourceRoots != form.addSourceRoots()
|| !ComparatorUtil.equalsNullable(myModuleName, form.getModule() == null ? null : form.getModule().getName())
|| !myWorkingDirectory.equals(form.getWorkingDirectory());
}
@@ -130,6 +138,8 @@ public class PyConsoleOptionsProvider implements PersistentStateComponent<PyCons
form.setInterpreterOptions(myInterpreterOptions);
form.setSdkHome(mySdkHome);
form.setUseModuleSdk(myUseModuleSdk);
form.addContentRoots(myAddContentRoots);
form.addSourceRoots(myAddSourceRoots);
boolean moduleWasAutoselected = false;
if (form.isUseModuleSdk() != myUseModuleSdk) {
myUseModuleSdk = form.isUseModuleSdk();
@@ -162,6 +172,15 @@ public class PyConsoleOptionsProvider implements PersistentStateComponent<PyCons
public Map<String, String> getEnvs() {
return myEnvs;
}
public boolean addContentRoots() {
return myAddContentRoots;
}
public boolean addSourceRoots() {
return myAddSourceRoots;
}
}
}
@@ -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<PythonC
private PydevConsoleCommunication myPydevConsoleCommunication;
private PyConsoleProcessHandler myProcessHandler;
private PydevConsoleExecuteActionHandler myConsoleExecuteActionHandler;
private List<ConsoleListener> myConsoleListeners = Lists.newArrayList();
private List<ConsoleListener> myConsoleListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private final PyConsoleType myConsoleType;
private Map<String, String> myEnvironmentVariables;
private String myCommandLine;
@@ -65,12 +65,12 @@ public class RunPythonConsoleAction extends AnAction implements DumbAware {
String[] setup_fragment;
Collection<String> pythonPath = PythonCommandLineState.collectPythonPath(module);
PyConsoleOptionsProvider.PyConsoleSettings settingsProvider = PyConsoleOptionsProvider.getInstance(project).getPythonConsoleSettings();
Collection<String> 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) {
@@ -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<Runnable> mySdkChangedListeners = new ArrayList<Runnable>();
private final List<Runnable> mySdkChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private final DirectoryProjectGenerator myGenerator;
private Sdk mySdk;
@@ -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());
}
@@ -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<Consumer<Sdk>> myPathChangedListeners = new ArrayList<Consumer<Sdk>>();
private final List<Consumer<Sdk>> myPathChangedListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private Set<String> currentlyInstalling = new HashSet<String>();
public PyPackagesPanel(Project project, PyPackagesNotificationPanel area) {
@@ -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;
@@ -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;
@@ -39,6 +39,8 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
private String myWorkingDirectory = "";
private String mySdkHome = "";
private boolean myUseModuleSdk;
private boolean myAddContentRoots;
private boolean myAddSourceRoots;
protected PathMappingSettings myMappingSettings;
public AbstractPythonRunConfiguration(final String name, final RunConfigurationModule module, final ConfigurationFactory factory) {
@@ -199,6 +201,8 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
mySdkHome = JDOMExternalizerUtil.readField(element, "SDK_HOME");
myWorkingDirectory = JDOMExternalizerUtil.readField(element, "WORKING_DIRECTORY");
myUseModuleSdk = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, "IS_MODULE_SDK"));
myAddContentRoots = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, "ADD_CONTENT_ROOTS"));
myAddSourceRoots = Boolean.parseBoolean(JDOMExternalizerUtil.readField(element, "ADD_SOURCE_ROOTS"));
getConfigurationModule().readExternal(element);
setMappingSettings(PathMappingSettings.readExternal(element));
@@ -221,6 +225,8 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
JDOMExternalizerUtil.writeField(element, "SDK_HOME", mySdkHome);
JDOMExternalizerUtil.writeField(element, "WORKING_DIRECTORY", myWorkingDirectory);
JDOMExternalizerUtil.writeField(element, "IS_MODULE_SDK", Boolean.toString(myUseModuleSdk));
JDOMExternalizerUtil.writeField(element, "ADD_CONTENT_ROOTS", Boolean.toString(myAddContentRoots));
JDOMExternalizerUtil.writeField(element, "ADD_SOURCE_ROOTS", Boolean.toString(myAddSourceRoots));
getConfigurationModule().writeExternal(element);
// extension settings:
@@ -266,6 +272,26 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
myUseModuleSdk = useModuleSdk;
}
@Override
public boolean addContentRoots() {
return myAddContentRoots;
}
@Override
public boolean addSourceRoots() {
return myAddSourceRoots;
}
@Override
public void addSourceRoots(boolean add) {
myAddSourceRoots = add;
}
@Override
public void addContentRoots(boolean add) {
myAddContentRoots = add;
}
public static void copyParams(AbstractPythonRunConfigurationParams source, AbstractPythonRunConfigurationParams target) {
target.setEnvs(new HashMap<String, String>(source.getEnvs()));
target.setInterpreterOptions(source.getInterpreterOptions());
@@ -275,6 +301,8 @@ public abstract class AbstractPythonRunConfiguration<T extends AbstractRunConfig
target.setModule(source.getModule());
target.setUseModuleSdk(source.isUseModuleSdk());
target.setMappingSettings(source.getMappingSettings());
target.addContentRoots(source.addContentRoots());
target.addSourceRoots(source.addSourceRoots());
}
/**
@@ -37,7 +37,10 @@ import com.jetbrains.python.facet.LibraryContributingFacet;
import com.jetbrains.python.facet.PythonPathContributingFacet;
import com.jetbrains.python.remote.PyRemoteSdkAdditionalData;
import com.jetbrains.python.remote.PythonRemoteInterpreterManager;
import com.jetbrains.python.sdk.*;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonEnvUtil;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.NotNull;
@@ -331,7 +334,7 @@ public abstract class PythonCommandLineState extends CommandLineState {
protected Collection<String> collectPythonPath() {
final Module module = myConfig.getModule();
Set<String> pythonPath = Sets.newHashSet(collectPythonPath(module));
Set<String> 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<String> collectPythonPath(@Nullable Module module) {
return collectPythonPath(module, true);
return collectPythonPath(module, true, true);
}
@NotNull
public static Collection<String> collectPythonPath(@Nullable Module module, final boolean addProjectRoots) {
public static Collection<String> collectPythonPath(@Nullable Module module, boolean addContentRoots,
boolean addSourceRoots) {
Collection<String> pythonPathList = Sets.newLinkedHashSet();
if (module != null && addProjectRoots) {
addLibrariesFromModule(module, pythonPathList);
if (module != null) {
Set<Module> dependencies = new HashSet<Module>();
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<String> 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) {
@@ -148,14 +148,12 @@ public class PythonTask {
}
protected List<String> setupPythonPath() {
return setupPythonPath(true);
return setupPythonPath(true, true);
}
protected List<String> setupPythonPath(final boolean addProjectRoot) {
protected List<String> setupPythonPath(final boolean addContent, final boolean addSource) {
final List<String> pythonPath = Lists.newArrayList(PythonCommandLineState.getAddedPaths(mySdk));
if (addProjectRoot) {
pythonPath.addAll(PythonCommandLineState.collectPythonPath(myModule));
}
pythonPath.addAll(PythonCommandLineState.collectPythonPath(myModule, addContent, addSource));
return pythonPath;
}
@@ -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;
}
}
@@ -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);
}
@@ -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());
}
@@ -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<String> collectPythonPath() {
List<String> pythonPath = new ArrayList<String>(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<String> getTestSpecs() {
List<String> specs = new ArrayList<String>();
@@ -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<String> collectPythonPath() {
List<String> pythonPath = new ArrayList<String>(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<String> getTestSpecs() {
List<String> specs = new ArrayList<String>();
@@ -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<String> collectPythonPath() {
List<String> pythonPath = new ArrayList<String>(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<String> getTestSpecs() {
List<String> specs = new ArrayList<String>();
@@ -0,0 +1,4 @@
from java.util import Collections
x = Collections.emptyList()
s = x.size()
@@ -1,2 +1,2 @@
def g(x : object=None ):
def g(x: object=None):
return x
@@ -1,3 +1,3 @@
def foo(a : object, b):
def foo(a: object, b):
a.
b = 1
@@ -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]);
}