From a7ac25ffa1298dd8d53f807889662763e4791a4c Mon Sep 17 00:00:00 2001 From: "Ilya.Kazakevich" Date: Fri, 4 Dec 2015 01:00:10 +0300 Subject: [PATCH] PY-9727: Initial commit for tox configuration * Tox configuration created * Tox helper added * Refactoting to support several runners --- python/helpers/pycharm/_jb_tox_runner.py | 68 ++++++++++++++ python/helpers/pycharm/tcmessages.py | 30 ++++++- python/helpers/pycharm/tcunittest.py | 8 +- python/helpers/pycharm/utrunner.py | 26 +++--- python/src/META-INF/python-core.xml | 2 + .../com/jetbrains/python/PythonHelper.java | 1 + .../testing/PyRerunFailedTestsAction.java | 1 + .../PythonTestCommandLineStateBase.java | 1 + .../PythonTestConfigurationProducer.java | 3 +- .../attest/PythonAtTestCommandLineState.java | 2 + .../PythonDocTestCommandLineState.java | 2 + .../PythonNoseTestCommandLineState.java | 2 + .../pytest/PyTestCommandLineState.java | 1 + .../testing/tox/PyToxCommandLineState.java | 47 ++++++++++ .../testing/tox/PyToxConfiguration.java | 52 +++++++++++ .../tox/PyToxConfigurationFactory.java | 45 ++++++++++ .../tox/PyToxConfigurationProducer.java | 43 +++++++++ .../tox/PyToxConfigurationSettings.java | 88 +++++++++++++++++++ .../testing/tox/PyToxConfigurationType.java | 58 ++++++++++++ .../python/testing/tox/package-info.java | 21 +++++ .../PythonUnitTestCommandLineState.java | 2 + 21 files changed, 487 insertions(+), 16 deletions(-) create mode 100644 python/helpers/pycharm/_jb_tox_runner.py create mode 100644 python/src/com/jetbrains/python/testing/tox/PyToxCommandLineState.java create mode 100644 python/src/com/jetbrains/python/testing/tox/PyToxConfiguration.java create mode 100644 python/src/com/jetbrains/python/testing/tox/PyToxConfigurationFactory.java create mode 100644 python/src/com/jetbrains/python/testing/tox/PyToxConfigurationProducer.java create mode 100644 python/src/com/jetbrains/python/testing/tox/PyToxConfigurationSettings.java create mode 100644 python/src/com/jetbrains/python/testing/tox/PyToxConfigurationType.java create mode 100644 python/src/com/jetbrains/python/testing/tox/package-info.java diff --git a/python/helpers/pycharm/_jb_tox_runner.py b/python/helpers/pycharm/_jb_tox_runner.py new file mode 100644 index 000000000000..b1b12bee5b3b --- /dev/null +++ b/python/helpers/pycharm/_jb_tox_runner.py @@ -0,0 +1,68 @@ +# coding=utf-8 +""" +Runs tox from current directory. +It supports any runner, but well-known runners (py.test and unittest) are switched to our internal runners to provide better support +""" +import sys +from tox import config as tox_config, session as tox_session +from tox.session import Reporter + +from tcmessages import TeamcityServiceMessages +import os + +helpers_dir = str(os.path.split(__file__)[0]) + +# List of local runners to use +_RUNNERS = {"unit2": [os.path.join(helpers_dir, "utrunner.py"), os.getcwd(), "true"]} + +teamcity = TeamcityServiceMessages() + + + +class _Reporter(Reporter): + def logaction_start(self, action): + super(_Reporter, self).logaction_start(action) + if action.activity == "getenv": + teamcity.testSuiteStarted(action.id) + self.current_suite = action.id + + def logaction_finish(self, action): + super(_Reporter, self).logaction_finish(action) + if action.activity == "runtests": + teamcity.testSuiteFinished(action.id) + + + def error(self, msg): + super(_Reporter, self).error(msg) + name = teamcity.current_test_name() + if name: + teamcity.testError(name, msg) + if name == teamcity.topmost_suite: + teamcity.testSuiteFinished(name) + else: + sys.stderr.write(msg) + + def skip(self, msg): + super(_Reporter, self).skip(msg) + name = teamcity.current_test_name() + if name: + teamcity.testFinished(name) + + + + +config = tox_config.parseconfig() +for env, tmp_config in config.envconfigs.items(): + if not tmp_config.setenv: + tmp_config.setenv = dict() + tmp_config.setenv.update({"_jb_do_not_call_enter_matrix": "1"}) + commands = tmp_config.commands + if isinstance(commands, list) and len(commands) == 1: + command_with_arguments = commands[0] + if command_with_arguments[0] in _RUNNERS: + command_with_arguments = _RUNNERS[command_with_arguments[0]] + tmp_config.commands = [command_with_arguments] + +session = tox_session.Session(config, Report=_Reporter) +teamcity.testMatrixEntered() +session.runcommand() \ No newline at end of file diff --git a/python/helpers/pycharm/tcmessages.py b/python/helpers/pycharm/tcmessages.py index a567ed5438e5..d9601da2129c 100644 --- a/python/helpers/pycharm/tcmessages.py +++ b/python/helpers/pycharm/tcmessages.py @@ -7,6 +7,14 @@ class TeamcityServiceMessages: def __init__(self, output=sys.stdout, prepend_linebreak=False): self.output = output self.prepend_linebreak = prepend_linebreak + self.test_stack = [] + """ + Names of tests + """ + self.topmost_suite = None + """ + Last suite we entered in + """ def escapeValue(self, value): if sys.version_info[0] <= 2 and isinstance(value, unicode): @@ -28,21 +36,27 @@ class TeamcityServiceMessages: def testSuiteStarted(self, suiteName, location=None): self.message('testSuiteStarted', name=suiteName, locationHint=location) + self.test_stack.append(suiteName) + self.topmost_suite = suiteName def testSuiteFinished(self, suiteName): self.message('testSuiteFinished', name=suiteName) + self.__pop_current_test() def testStarted(self, testName, location=None): self.message('testStarted', name=testName, locationHint=location) + self.test_stack.append(testName) + def testFinished(self, testName, duration=None): self.message('testFinished', name=testName, duration=duration) + self.__pop_current_test() + def testIgnored(self, testName, message=''): self.message('testIgnored', name=testName, message=message) self.testFinished(testName) - def testFailed(self, testName, message='', details='', expected='', actual='', duration=None): """ Marks test as failed. *CAUTION*: This method calls ``testFinished``, so you do not need @@ -56,10 +70,24 @@ class TeamcityServiceMessages: self.message('testFailed', name=testName, message=message, details=details) self.testFinished(testName, int(duration) if duration else None) + + def __pop_current_test(self): + try: + self.test_stack.pop() + except IndexError: + pass + def testError(self, testName, message='', details='', duration=None): self.message('testFailed', name=testName, message=message, details=details, error="true") self.testFinished(testName, int(duration) if duration else None) + + def current_test_name(self): + """ + :return: name of current test we are in + """ + return self.test_stack[-1] if len(self.test_stack) > 0 else None + def testStdOut(self, testName, out): self.message('testStdOut', name=testName, out=out) diff --git a/python/helpers/pycharm/tcunittest.py b/python/helpers/pycharm/tcunittest.py index b688d804c653..185c12898a1e 100644 --- a/python/helpers/pycharm/tcunittest.py +++ b/python/helpers/pycharm/tcunittest.py @@ -1,3 +1,4 @@ +import os import traceback, sys from unittest import TestResult import datetime @@ -37,13 +38,18 @@ def smart_str(s): class TeamcityTestResult(TestResult): + """ + Set ``_jb_do_not_call_enter_matrix`` to prevent it from runnig "enter matrix" + """ + def __init__(self, stream=sys.stdout, *args, **kwargs): TestResult.__init__(self) for arg, value in kwargs.items(): setattr(self, arg, value) self.output = stream self.messages = TeamcityServiceMessages(self.output, prepend_linebreak=True) - self.messages.testMatrixEntered() + if not "_jb_do_not_call_enter_matrix" in os.environ: + self.messages.testMatrixEntered() self.current_failed = False self.current_suite = None self.subtest_suite = None diff --git a/python/helpers/pycharm/utrunner.py b/python/helpers/pycharm/utrunner.py index bd04fedcff53..dfaaad58e12a 100644 --- a/python/helpers/pycharm/utrunner.py +++ b/python/helpers/pycharm/utrunner.py @@ -38,6 +38,8 @@ def loadSource(fileName): cnt += 1 moduleName = getModuleName(prefix, cnt) debug("/ Loading " + fileName + " as " + moduleName) + if os.path.isdir(fileName): + fileName = fileName + os.path.sep module = imp.load_source(moduleName, fileName) modules[moduleName] = module return module @@ -56,17 +58,15 @@ def walkModules(modulesAndPattern, dirname, names): # For default pattern see https://docs.python.org/2/library/unittest.html#test-discovery def loadModulesFromFolderRec(folder, pattern="test*.py"): modules = [] - if PYTHON_VERSION_MAJOR == 3: - # fnmatch converts glob to regexp - prog_list = [re.compile(fnmatch.translate(pat.strip())) for pat in pattern.split(',')] - for root, dirs, files in os.walk(folder): - for name in files: - for prog in prog_list: - if name.endswith(".py") and prog.match(name): - modules.append(loadSource(os.path.join(root, name))) - else: # actually for jython compatibility - os.path.walk(folder, walkModules, (modules, pattern)) - + # fnmatch converts glob to regexp + prog_list = [re.compile(fnmatch.translate(pat.strip())) for pat in pattern.split(',')] + for root, dirs, files in os.walk(folder): + files = [f for f in files if not f[0] == '.'] + dirs[:] = [d for d in dirs if not d[0] == '.'] + for name in files: + for prog in prog_list: + if name.endswith(".py") and prog.match(name): + modules.append(loadSource(os.path.join(root, name))) return modules testLoader = TestLoader() @@ -109,11 +109,11 @@ if __name__ == "__main__": a_splitted = a[0].split("_args_separator_") # ";" can't be used with bash, so we use "_args_separator_" if len(a_splitted) != 1: # means we have pattern to match against - if a_splitted[0].endswith(os.path.sep): + if os.path.isdir(a_splitted[0]): debug("/ from folder " + a_splitted[0] + ". Use pattern: " + a_splitted[1]) modules = loadModulesFromFolderRec(a_splitted[0], a_splitted[1]) else: - if a[0].endswith(os.path.sep): + if os.path.isdir(a[0]): debug("/ from folder " + a[0]) modules = loadModulesFromFolderRec(a[0]) else: diff --git a/python/src/META-INF/python-core.xml b/python/src/META-INF/python-core.xml index 952fc1fe3e9c..12ef08852ae2 100644 --- a/python/src/META-INF/python-core.xml +++ b/python/src/META-INF/python-core.xml @@ -137,10 +137,12 @@ + + diff --git a/python/src/com/jetbrains/python/PythonHelper.java b/python/src/com/jetbrains/python/PythonHelper.java index 3816e5ba9f04..1eee40c98919 100644 --- a/python/src/com/jetbrains/python/PythonHelper.java +++ b/python/src/com/jetbrains/python/PythonHelper.java @@ -50,6 +50,7 @@ public enum PythonHelper implements HelperPackage { // Test runners UT("pycharm", "utrunner"), + TOX("pycharm", "_jb_tox_runner"), SETUPPY("pycharm", "pycharm_setup_runner"), NOSE("pycharm", "noserunner"), PYTEST("pycharm", "pytestrunner"), diff --git a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java index 5beca8a17bae..8dea7e5b2479 100644 --- a/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java +++ b/python/src/com/jetbrains/python/testing/PyRerunFailedTestsAction.java @@ -104,6 +104,7 @@ public class PyRerunFailedTestsAction extends AbstractRerunFailedTestsAction { return myState.getRunner(); } + @NotNull @Override protected List getTestSpecs() { List specs = new ArrayList(); diff --git a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java index b702b94b77d6..103f2a0856ec 100644 --- a/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java +++ b/python/src/com/jetbrains/python/testing/PythonTestCommandLineStateBase.java @@ -173,5 +173,6 @@ public abstract class PythonTestCommandLineStateBase extends PythonCommandLineSt } protected abstract HelperPackage getRunner(); + @NotNull protected abstract List getTestSpecs(); } diff --git a/python/src/com/jetbrains/python/testing/PythonTestConfigurationProducer.java b/python/src/com/jetbrains/python/testing/PythonTestConfigurationProducer.java index 10f7e018d1fc..21ab8076ab84 100644 --- a/python/src/com/jetbrains/python/testing/PythonTestConfigurationProducer.java +++ b/python/src/com/jetbrains/python/testing/PythonTestConfigurationProducer.java @@ -17,6 +17,7 @@ package com.jetbrains.python.testing; import com.google.common.collect.Sets; import com.intellij.execution.Location; +import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.ConfigurationFromContext; import com.intellij.execution.actions.RunConfigurationProducer; @@ -58,7 +59,7 @@ abstract public class PythonTestConfigurationProducer extends RunConfigurationPr super(configurationFactory); } - @Override + @Override public boolean isConfigurationFromContext(AbstractPythonTestRunConfiguration configuration, ConfigurationContext context) { final Location location = context.getLocation(); if (location == null || !isAvailable(location)) return false; diff --git a/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java b/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java index cfe65d3067a1..c0c0a93e8485 100644 --- a/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/attest/PythonAtTestCommandLineState.java @@ -19,6 +19,7 @@ import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.openapi.util.io.FileUtil; import com.jetbrains.python.PythonHelper; import com.jetbrains.python.testing.PythonTestCommandLineStateBase; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -40,6 +41,7 @@ public class PythonAtTestCommandLineState extends PythonTestCommandLineStateBase return PythonHelper.ATTEST; } + @NotNull 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 a47242aad107..e12e93d3edab 100644 --- a/python/src/com/jetbrains/python/testing/doctest/PythonDocTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/doctest/PythonDocTestCommandLineState.java @@ -18,6 +18,7 @@ package com.jetbrains.python.testing.doctest; import com.intellij.execution.runners.ExecutionEnvironment; import com.jetbrains.python.PythonHelper; import com.jetbrains.python.testing.PythonTestCommandLineStateBase; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -39,6 +40,7 @@ public class PythonDocTestCommandLineState extends PythonTestCommandLineStateBas return PythonHelper.DOCSTRING; } + @NotNull protected List getTestSpecs() { List specs = new ArrayList(); diff --git a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestCommandLineState.java b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestCommandLineState.java index 4d9393b8cedd..0dc5647eac16 100644 --- a/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/nosetest/PythonNoseTestCommandLineState.java @@ -22,6 +22,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.jetbrains.python.PythonHelper; import com.jetbrains.python.testing.PythonTestCommandLineStateBase; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -42,6 +43,7 @@ public class PythonNoseTestCommandLineState extends PythonTestCommandLineStateBa return PythonHelper.NOSE; } + @NotNull protected List getTestSpecs() { List specs = new ArrayList(); diff --git a/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java b/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java index dd202187e83c..d44a93508554 100644 --- a/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/pytest/PyTestCommandLineState.java @@ -55,6 +55,7 @@ public class PyTestCommandLineState extends PythonTestCommandLineStateBase { return PythonHelper.PYTEST; } + @NotNull @Override protected List getTestSpecs() { List specs = new ArrayList(); diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxCommandLineState.java b/python/src/com/jetbrains/python/testing/tox/PyToxCommandLineState.java new file mode 100644 index 000000000000..5025ce19fe11 --- /dev/null +++ b/python/src/com/jetbrains/python/testing/tox/PyToxCommandLineState.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.testing.tox; + +import com.intellij.execution.runners.ExecutionEnvironment; +import com.jetbrains.python.HelperPackage; +import com.jetbrains.python.PythonHelper; +import com.jetbrains.python.testing.PythonTestCommandLineStateBase; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * @author Ilya.Kazakevich + */ +class PyToxCommandLineState extends PythonTestCommandLineStateBase { + + public PyToxCommandLineState(PyToxConfiguration configuration, + ExecutionEnvironment environment) { + super(configuration, environment); + } + + @Override + protected HelperPackage getRunner() { + return PythonHelper.TOX; + } + + @NotNull + @Override + protected List getTestSpecs() { + return Collections.emptyList(); + } +} diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxConfiguration.java b/python/src/com/jetbrains/python/testing/tox/PyToxConfiguration.java new file mode 100644 index 000000000000..04568c2069d8 --- /dev/null +++ b/python/src/com/jetbrains/python/testing/tox/PyToxConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.testing.tox; + +import com.intellij.execution.Executor; +import com.intellij.execution.configurations.RunProfileState; +import com.intellij.execution.runners.ExecutionEnvironment; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.jetbrains.python.run.AbstractPythonRunConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * @author Ilya.Kazakevich + */ +final class PyToxConfiguration extends AbstractPythonRunConfiguration { + + @NotNull + private final Project myProject; + + PyToxConfiguration(@NotNull final PyToxConfigurationFactory factory, @NotNull final Project project) { + super(project, factory); + myProject = project; + } + + + @Override + protected SettingsEditor createConfigurationEditor() { + return new PyToxConfigurationSettings(myProject); + } + + @Nullable + @Override + public RunProfileState getState(@NotNull final Executor executor, @NotNull final ExecutionEnvironment environment) { + getWorkingDirectory(); + return new PyToxCommandLineState(this, environment); + } +} diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationFactory.java b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationFactory.java new file mode 100644 index 000000000000..faaae776ee47 --- /dev/null +++ b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationFactory.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.testing.tox; + +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.ConfigurationType; +import com.intellij.execution.configurations.RunConfiguration; +import com.intellij.openapi.project.Project; +import com.jetbrains.python.run.PythonConfigurationFactoryBase; +import org.jetbrains.annotations.NotNull; + +/** + * @author Ilya.Kazakevich + */ +public final class PyToxConfigurationFactory extends PythonConfigurationFactoryBase { + public static final ConfigurationFactory INSTANCE = new PyToxConfigurationFactory(PyToxConfigurationType.INSTANCE); + + public PyToxConfigurationFactory(@NotNull final ConfigurationType type) { + super(type); + } + + @Override + public String getName() { + return "Tox"; + } + + @NotNull + @Override + public RunConfiguration createTemplateConfiguration(@NotNull final Project project) { + return new PyToxConfiguration(this, project); + } +} diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationProducer.java b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationProducer.java new file mode 100644 index 000000000000..a80cbe2a51b3 --- /dev/null +++ b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationProducer.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.testing.tox; + +import com.intellij.execution.actions.ConfigurationContext; +import com.intellij.execution.actions.RunConfigurationProducer; +import com.intellij.openapi.util.Ref; +import com.intellij.psi.PsiElement; + +/** + * @author Ilya.Kazakevich + */ +public final class PyToxConfigurationProducer extends RunConfigurationProducer { + + public PyToxConfigurationProducer() { + super(PyToxConfigurationFactory.INSTANCE); + } + + @Override + public boolean isConfigurationFromContext(PyToxConfiguration configuration, ConfigurationContext context) { + return false; + } + + @Override + protected boolean setupConfigurationFromContext(PyToxConfiguration configuration, + ConfigurationContext context, + Ref sourceElement) { + return false; + } +} diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationSettings.java b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationSettings.java new file mode 100644 index 000000000000..1b5691470144 --- /dev/null +++ b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationSettings.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.testing.tox; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SettingsEditor; +import com.intellij.openapi.project.Project; +import com.jetbrains.python.run.AbstractPyCommonOptionsForm; +import com.jetbrains.python.run.AbstractPythonRunConfiguration; +import com.jetbrains.python.run.PyCommonOptionsFormData; +import com.jetbrains.python.run.PyCommonOptionsFormFactory; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.util.List; + +/** + * @author Ilya.Kazakevich + */ +final class PyToxConfigurationSettings extends SettingsEditor { + @NotNull + private final Project myProject; + private AbstractPyCommonOptionsForm myForm; + + PyToxConfigurationSettings(@NotNull final Project project) { + myProject = project; + } + + @Override + protected void applyEditorTo(final PyToxConfiguration s) throws ConfigurationException { + AbstractPythonRunConfiguration.copyParams(myForm, s); + } + + @Override + protected void resetEditorFrom(final PyToxConfiguration s) { + AbstractPythonRunConfiguration.copyParams(s, myForm); + } + + @NotNull + @Override + protected JComponent createEditor() { + + final JPanel panel = new JPanel(new BorderLayout()); + panel.add(new JLabel("Tox"), BorderLayout.PAGE_START); + + myForm = createEnvPanel(); + final JComponent envPanel = myForm.getMainPanel(); + + panel.add(envPanel, BorderLayout.PAGE_END); + + return panel; + } + + @NotNull + private AbstractPyCommonOptionsForm createEnvPanel() { + return PyCommonOptionsFormFactory.getInstance().createForm(new PyCommonOptionsFormData() { + @Override + public Project getProject() { + return myProject; + } + + @Override + public List getValidModules() { + return AbstractPythonRunConfiguration.getValidModules(myProject); + } + + @Override + public boolean showConfigureInterpretersLink() { + return false; + } + }); + } +} diff --git a/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationType.java b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationType.java new file mode 100644 index 000000000000..afe9ef3b97aa --- /dev/null +++ b/python/src/com/jetbrains/python/testing/tox/PyToxConfigurationType.java @@ -0,0 +1,58 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.testing.tox; + +import com.intellij.execution.configurations.ConfigurationFactory; +import com.intellij.execution.configurations.ConfigurationType; +import icons.PythonIcons; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author Ilya.Kazakevich + */ +public class PyToxConfigurationType implements ConfigurationType { + + public static final String ID = "tox"; + public static final ConfigurationType INSTANCE = new PyToxConfigurationType(); + + @Override + public ConfigurationFactory[] getConfigurationFactories() { + return new ConfigurationFactory[]{new PyToxConfigurationFactory(this)}; + } + + @Override + public String getDisplayName() { + return "tox"; + } + + @Override + public String getConfigurationTypeDescription() { + return "Tox runner"; + } + + @Override + public Icon getIcon() { + return PythonIcons.Python.PythonTests; + } + + @NotNull + @Override + public String getId() { + return ID; + } +} diff --git a/python/src/com/jetbrains/python/testing/tox/package-info.java b/python/src/com/jetbrains/python/testing/tox/package-info.java new file mode 100644 index 000000000000..f6ca14dbfe6e --- /dev/null +++ b/python/src/com/jetbrains/python/testing/tox/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * tox test runner + * @author Ilya.Kazakevich + */ +package com.jetbrains.python.testing.tox; \ No newline at end of file diff --git a/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java b/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java index 8ecc4d60a7d0..1915371a6f6a 100644 --- a/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java +++ b/python/src/com/jetbrains/python/testing/unittest/PythonUnitTestCommandLineState.java @@ -24,6 +24,7 @@ import com.jetbrains.python.PyNames; import com.jetbrains.python.PythonHelper; import com.jetbrains.python.testing.AbstractPythonTestRunConfiguration; import com.jetbrains.python.testing.PythonTestCommandLineStateBase; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; @@ -49,6 +50,7 @@ public class PythonUnitTestCommandLineState extends return PythonHelper.UT; } + @NotNull protected List getTestSpecs() { List specs = new ArrayList();