PY-43632: Fix python tests localization

Previous solution was kinda messy and buggy.
i18n now moved to ConfigField

GitOrigin-RevId: 4d1696067bd4c69e1b7c194533085a33652b8d61
This commit is contained in:
Ilya.Kazakevich
2020-08-03 12:31:33 +00:00
committed by intellij-monorepo-bot
parent 140716499d
commit d333306575
8 changed files with 75 additions and 87 deletions
@@ -269,22 +269,28 @@ runcfg.tests.empty_suite=Empty suite
runcfg.doctest.display_name=Doctests
runcfg.doctest.description=Python's doctests run configuration
runcfg.python_tests.config.additionalArguments=Additional Arguments
runcfg.python_tests.config.target=Target
runcfg.python_tests.config.targetType=Target Type
### nosetests run conf
runcfg.nosetests.display_name=Nosetests
runcfg.nosetests.description=Python's nosetests run configuration
### nosetests run configuration custom options
python.testing.nose.custom.options.regex.pattern=Regex Pattern:
python.testing.nose.custom.options.keywords=Keywords:
python.testing.nose.custom.options.parameters=Parameters:
python.testing.nose.custom.options.additional.arguments=Additional Arguments:
runcfg.nosetests.config.regexPattern=Regex Pattern
### pytest run conf
runcfg.pytest.display_name=pytest
# deprecated start
runcfg.pytest.description=pytest run configuration
runcfg.pytest.target=&Target:
runcfg.pytest.parameters=&Options:
runcfg.pytest.keywords=&Keywords:
# deprecated end
runcfg.pytest.config.keywords=Keywords
runcfg.pytest.config.parameters=Parameters
### trial run conf
runcfg.trial.display_name=Twisted Trial
@@ -298,6 +304,8 @@ runcfg.tox.runner=tox runner
runcfg.tox=tox
### unittest run configuration
runcfg.unittest.config.pattern=Pattern
runcfg.unittest.display_name=Unittests
runcfg.unittest.description=Python's unittest run configuration
runcfg.unittest.no_script_name=Please specify script name
@@ -1109,4 +1117,4 @@ python.compatibility.inspection.advertiser.version.stale.python3.version.warning
python.install.framework.ensure.installed=Ensuring {0} is installed
python.install.framework.checking.is.installed=Checking if {0} is installed...
python.install.framework.installing=Installing {0}...
py.commandline.configure=Confiures Python SDKs for the project
py.commandline.configure=Confiures Python SDKs for the project
@@ -6,7 +6,6 @@ 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.PyBundle
import com.jetbrains.python.PyNames
import com.jetbrains.python.PythonHelper
import com.jetbrains.python.run.targetBasedConfiguration.PyRunTargetVariant
@@ -17,10 +16,8 @@ import com.jetbrains.python.run.targetBasedConfiguration.PyRunTargetVariant
class PyNoseTestSettingsEditor(configuration: PyAbstractTestConfiguration) :
PyAbstractTestSettingsEditor(
PyTestSharedForm.create(configuration, PyTestSharedForm.CustomOption(
PyNoseTestConfiguration::regexPattern.name,
PyBundle.message("python.testing.nose.custom.options.regex.pattern"),
PyRunTargetVariant.PATH)))
PyTestSharedForm.create(configuration, PyTestCustomOption(
PyNoseTestConfiguration::regexPattern, PyRunTargetVariant.PATH)))
class PyNoseTestExecutionEnvironment(configuration: PyNoseTestConfiguration, environment: ExecutionEnvironment) :
PyTestExecutionEnvironment<PyNoseTestConfiguration>(configuration, environment) {
@@ -31,7 +28,7 @@ class PyNoseTestExecutionEnvironment(configuration: PyNoseTestConfiguration, env
class PyNoseTestConfiguration(project: Project, factory: PyNoseTestFactory) :
PyAbstractTestConfiguration(project, factory, PyTestFrameworkService.getSdkReadableNameByFramework(PyNames.NOSE_TEST)),
PyTestConfigurationWithCustomSymbol {
@ConfigField
@ConfigField("runcfg.nosetests.config.regexPattern")
var regexPattern: String = ""
override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? =
@@ -25,7 +25,6 @@ import com.intellij.openapi.options.SettingsEditor
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Pair
import com.intellij.psi.search.GlobalSearchScope
import com.jetbrains.python.PyBundle
import com.jetbrains.python.PyNames
import com.jetbrains.python.PythonHelper
import com.intellij.execution.target.value.TargetEnvironmentFunction
@@ -45,18 +44,8 @@ class PyTestSettingsEditor(configuration: PyAbstractTestConfiguration) :
PyAbstractTestSettingsEditor(
create(
configuration,
CustomOption(
PyTestConfiguration::keywords.name,
PyBundle.message("python.testing.nose.custom.options.keywords"),
PyRunTargetVariant.PATH,
PyRunTargetVariant.PYTHON
),
CustomOption(
PyTestConfiguration::parameters.name,
PyBundle.message("python.testing.nose.custom.options.parameters"),
PyRunTargetVariant.PATH,
PyRunTargetVariant.PYTHON
)
PyTestCustomOption(PyTestConfiguration::keywords, PyRunTargetVariant.PATH, PyRunTargetVariant.PYTHON),
PyTestCustomOption(PyTestConfiguration::parameters, PyRunTargetVariant.PATH, PyRunTargetVariant.PYTHON)
))
class PyPyTestExecutionEnvironment(configuration: PyTestConfiguration, environment: ExecutionEnvironment) :
@@ -80,10 +69,10 @@ class PyPyTestExecutionEnvironment(configuration: PyTestConfiguration, environme
class PyTestConfiguration(project: Project, factory: PyTestFactory)
: PyAbstractTestConfiguration(project, factory, PyTestFrameworkService.getSdkReadableNameByFramework(PyNames.PY_TEST)),
PyTestConfigurationWithCustomSymbol {
@ConfigField
@ConfigField("runcfg.pytest.config.keywords")
var keywords: String = ""
@ConfigField
@ConfigField("runcfg.pytest.config.parameters")
var parameters: String = ""
override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? =
@@ -0,0 +1,26 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.testing
import com.jetbrains.python.PyBundle
import com.jetbrains.python.run.targetBasedConfiguration.PyRunTargetVariant
import org.jetbrains.annotations.Nls
import java.util.*
import kotlin.reflect.KCallable
internal class PyTestCustomOption(property: KCallable<*>, vararg supportedTypes: PyRunTargetVariant) {
val name: String = property.name
@field:Nls
val localizedName: String
init {
localizedName = property.annotations.filterIsInstance<ConfigField>().firstOrNull()?.localizedName?.let {
PyBundle.message(it)
} ?: name
}
/**
* Types to display this option for
*/
val mySupportedTypes: EnumSet<PyRunTargetVariant> = EnumSet.copyOf(supportedTypes.asList())
}
@@ -84,7 +84,7 @@ class PyTestLegacyConfigurationAdapter<in T : PyAbstractTestConfiguration>(newCo
*
* Null means "false" and used here to prevent saving useless "false" value in .xml for new configurations.
*/
@ConfigField
@ConfigField("runcfg.pytest.config.parameters") // Fake i18n, which will be deleted soon along with outdated code
var legacyInformationCopiedToNew: Boolean? = null
init {
@@ -34,7 +34,6 @@ import com.jetbrains.PySymbolFieldWithBrowseButton;
import com.jetbrains.extensions.ContextAnchor;
import com.jetbrains.extensions.ModuleBasedContextAnchor;
import com.jetbrains.extensions.ProjectSdkContextAnchor;
import com.jetbrains.python.PyBundle;
import com.jetbrains.python.psi.types.TypeEvalContext;
import com.jetbrains.python.run.AbstractPyCommonOptionsForm;
import com.jetbrains.python.run.PyBrowseActionListener;
@@ -42,7 +41,6 @@ import com.jetbrains.python.run.PyCommonOptionsFormFactory;
import com.jetbrains.python.run.targetBasedConfiguration.PyRunTargetVariant;
import com.jetbrains.reflection.ReflectionUtilsKt;
import com.jetbrains.reflection.SimplePropertiesProvider;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -55,17 +53,12 @@ import java.util.regex.Pattern;
/**
* Form to display run configuration.
* It displays target type, target, additional arguments, custom options (if provided) and environment options
* Create with {@link #create(PyAbstractTestConfiguration, CustomOption...)}}
* Create with {@link #create(PyAbstractTestConfiguration, PyTestCustomOption...)}}
*
* @author Ilya.Kazakevich
*/
public final class PyTestSharedForm implements SimplePropertiesProvider {
/**
* Regex to convert additionalArgumentNames to "Additional Argument Names"
*/
private static final Pattern CAPITAL_LETTER = Pattern.compile("(?=\\p{Upper})");
private JPanel myPanel;
/**
* Panel for test targets
@@ -150,7 +143,7 @@ public final class PyTestSharedForm implements SimplePropertiesProvider {
*/
@NotNull
public static PyTestSharedForm create(@NotNull final PyAbstractTestConfiguration configuration,
final CustomOption @NotNull ... customOptions) {
final PyTestCustomOption @NotNull ... customOptions) {
final PyTestSharedForm form = new PyTestSharedForm(configuration.getModule(), configuration);
for (final PyRunTargetVariant testTargetType : PyRunTargetVariant.values()) {
@@ -171,23 +164,22 @@ public final class PyTestSharedForm implements SimplePropertiesProvider {
setBorderToPanel(form.myPanel, configuration.getTestFrameworkName());
form.addCustomOptions(
ObjectArrays.concat(customOptions, new CustomOption(
PyTestsSharedKt.getAdditionalArgumentsPropertyName(),
PyBundle.message("python.testing.nose.custom.options.additional.arguments"),
ObjectArrays.concat(customOptions, new PyTestCustomOption(
PyTestsSharedKt.getAdditionalArgumentsProperty(),
PyRunTargetVariant.values()))
);
configuration.copyTo(ReflectionUtilsKt.getProperties(form, null, true));
return form;
}
private void addCustomOptions(final CustomOption @NotNull ... customOptions) {
private void addCustomOptions(final PyTestCustomOption @NotNull ... customOptions) {
if (customOptions.length == 0) {
return;
}
final Map<String, JBTextField> optionValueFields = new HashMap<>();
for (final CustomOption option : customOptions) {
for (final PyTestCustomOption option : customOptions) {
final JBTextField textField = new JBTextField();
optionValueFields.put(option.myName, textField);
optionValueFields.put(option.getName(), textField);
}
final GridBagConstraints constraints = new GridBagConstraints();
@@ -195,9 +187,9 @@ public final class PyTestSharedForm implements SimplePropertiesProvider {
constraints.gridy = 0;
constraints.anchor = GridBagConstraints.LINE_START;
for (final CustomOption option : customOptions) {
final JBTextField textField = optionValueFields.get(option.myName);
final JLabel label = new JLabel(option.myLocalizedName);
for (final PyTestCustomOption option : customOptions) {
final JBTextField textField = optionValueFields.get(option.getName());
final JLabel label = new JLabel(option.getLocalizedName());
label.setHorizontalAlignment(SwingConstants.LEFT);
constraints.fill = GridBagConstraints.NONE;
@@ -212,7 +204,7 @@ public final class PyTestSharedForm implements SimplePropertiesProvider {
constraints.gridy++;
myCustomOptions.put(option.myName, new OptionHolder(option, label, textField));
myCustomOptions.put(option.getName(), new OptionHolder(option, label, textField));
}
}
@@ -278,38 +270,16 @@ public final class PyTestSharedForm implements SimplePropertiesProvider {
onTargetTypeChanged();
}
static final class CustomOption {
/**
* Option name
*/
@NotNull
private final String myName;
private final @NotNull @Nls String myLocalizedName;
/**
* Types to display this option for
*/
private final EnumSet<PyRunTargetVariant> mySupportedTypes;
CustomOption(@NotNull final String name,
@NotNull @Nls String localizedName,
final PyRunTargetVariant @NotNull ... supportedTypes) {
myName = name;
myLocalizedName = localizedName;
mySupportedTypes = EnumSet.copyOf(Arrays.asList(supportedTypes));
}
}
private static final class OptionHolder {
@NotNull
private final CustomOption myOption;
private final PyTestCustomOption myOption;
@NotNull
private final JLabel myOptionLabel;
@NotNull
private final JTextField myOptionValue;
private OptionHolder(@NotNull final CustomOption option,
private OptionHolder(@NotNull final PyTestCustomOption option,
@NotNull final JLabel optionLabel,
@NotNull final JTextField optionValue) {
myOption = option;
@@ -318,7 +288,7 @@ public final class PyTestSharedForm implements SimplePropertiesProvider {
}
private void setType(@NotNull final PyRunTargetVariant type) {
final boolean visible = myOption.mySupportedTypes.contains(type);
final boolean visible = myOption.getMySupportedTypes().contains(type);
myOptionLabel.setVisible(visible);
myOptionValue.setVisible(visible);
}
@@ -58,6 +58,7 @@ import com.jetbrains.reflection.getProperties
import jetbrains.buildServer.messages.serviceMessages.ServiceMessage
import jetbrains.buildServer.messages.serviceMessages.TestStdErr
import jetbrains.buildServer.messages.serviceMessages.TestStdOut
import org.jetbrains.annotations.PropertyKey
import java.util.regex.Matcher
/**
@@ -83,7 +84,7 @@ fun processTCMessage(text: String): String {
}
}
internal fun getAdditionalArgumentsPropertyName() = com.jetbrains.python.testing.PyAbstractTestConfiguration::additionalArguments.name
internal fun getAdditionalArgumentsProperty() = PyAbstractTestConfiguration::additionalArguments
/**
* If runner name is here that means test runner only can run inheritors for TestCase
@@ -101,7 +102,7 @@ fun isTestElement(element: PsiElement, testCaseClassRequired: ThreeState, typeEv
it is PyFile && PythonUnitTestDetectorsBasedOnSettings.isTestFile(it, testCaseClassRequired, typeEvalContext)
}
is PyFunction -> PythonUnitTestDetectorsBasedOnSettings.isTestFunction(element,
testCaseClassRequired, typeEvalContext)
testCaseClassRequired, typeEvalContext)
is com.jetbrains.python.psi.PyClass -> {
PythonUnitTestDetectorsBasedOnSettings.isTestClass(element, testCaseClassRequired, typeEvalContext)
}
@@ -272,8 +273,8 @@ private const val DEFAULT_PATH = ""
/**
* Target depends on target type. It could be path to file/folder or python target
*/
data class ConfigurationTarget(@ConfigField override var target: String,
@ConfigField override var targetType: PyRunTargetVariant) : TargetWithVariant {
data class ConfigurationTarget(@ConfigField("runcfg.python_tests.config.target") override var target: String,
@ConfigField("runcfg.python_tests.config.targetType") override var targetType: PyRunTargetVariant) : TargetWithVariant {
fun copyTo(dst: ConfigurationTarget) {
// TODO: do we have such method it in Kotlin?
dst.target = target
@@ -401,6 +402,7 @@ internal interface PyTestConfigurationWithCustomSymbol {
* Separates file part and symbol
*/
val fileSymbolSeparator: String
/**
* Separates parts of symbol name
*/
@@ -429,7 +431,8 @@ abstract class PyAbstractTestConfiguration(project: Project,
@DelegationProperty
val target: ConfigurationTarget = ConfigurationTarget(DEFAULT_PATH, PyRunTargetVariant.PATH)
@ConfigField
@ConfigField("runcfg.python_tests.config.additionalArguments")
var additionalArguments: String = ""
val testFrameworkName: String = configurationFactory.name
@@ -862,6 +865,6 @@ internal class PyTestsConfigurationProducer : AbstractPythonTestConfigurationPro
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
/**
* Mark run configuration field with it to enable saving, resotring and form iteraction
* Mark run configuration field with it to enable saving, restoring and form iteraction
*/
annotation class ConfigField
annotation class ConfigField(@param:PropertyKey(resourceBundle = PyBundle.BUNDLE) val localizedName: String)
@@ -36,12 +36,7 @@ import com.jetbrains.python.run.targetBasedConfiguration.PyRunTargetVariant
class PyUnitTestSettingsEditor(configuration: PyAbstractTestConfiguration) :
PyAbstractTestSettingsEditor(
PyTestSharedForm.create(configuration,
PyTestSharedForm.CustomOption(
PyUnitTestConfiguration::pattern.name,
PyBundle.message("python.testing.nose.custom.options.additional.arguments"),
PyRunTargetVariant.PATH
)
))
PyTestCustomOption(PyUnitTestConfiguration::pattern, PyRunTargetVariant.PATH)))
class PyUnitTestExecutionEnvironment(configuration: PyUnitTestConfiguration, environment: ExecutionEnvironment) :
PyTestExecutionEnvironment<PyUnitTestConfiguration>(configuration, environment) {
@@ -61,7 +56,7 @@ class PyUnitTestExecutionEnvironment(configuration: PyUnitTestConfiguration, env
class PyUnitTestConfiguration(project: Project, factory: PyUnitTestFactory) :
PyAbstractTestConfiguration(project, factory,
PythonTestConfigurationsModel.getPythonsUnittestName()) { // Bare functions not supported in unittest: classes only
@ConfigField
@ConfigField("runcfg.unittest.config.pattern")
var pattern: String? = null
override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState? =