From 25bfcc7c8a49d283cd779b3e8f533fcba149bbbd Mon Sep 17 00:00:00 2001
From: Guillaume Dequenne
Date: Mon, 6 Jul 2020 10:47:46 +0200
Subject: [PATCH 1/5] Prepare for next development iteration
---
its/plugin/it-python-plugin-test/pom.xml | 2 +-
its/plugin/pom.xml | 2 +-
its/plugin/python-custom-rules-plugin/pom.xml | 2 +-
its/pom.xml | 2 +-
its/ruling/pom.xml | 2 +-
pom.xml | 2 +-
python-checks-testkit/pom.xml | 2 +-
python-checks/pom.xml | 2 +-
python-frontend/pom.xml | 2 +-
sonar-python-plugin/pom.xml | 2 +-
10 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/its/plugin/it-python-plugin-test/pom.xml b/its/plugin/it-python-plugin-test/pom.xml
index 4b8305cc49..dfa5da2cd3 100644
--- a/its/plugin/it-python-plugin-test/pom.xml
+++ b/its/plugin/it-python-plugin-test/pom.xml
@@ -7,7 +7,7 @@
it-python-plugin
org.sonarsource.python
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
it-python-plugin-test
diff --git a/its/plugin/pom.xml b/its/plugin/pom.xml
index dd81260a88..64f84cc6c8 100644
--- a/its/plugin/pom.xml
+++ b/its/plugin/pom.xml
@@ -5,7 +5,7 @@
org.sonarsource.python
python-its
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
diff --git a/its/plugin/python-custom-rules-plugin/pom.xml b/its/plugin/python-custom-rules-plugin/pom.xml
index 916ce7c703..b199bc8e38 100644
--- a/its/plugin/python-custom-rules-plugin/pom.xml
+++ b/its/plugin/python-custom-rules-plugin/pom.xml
@@ -6,7 +6,7 @@
org.sonarsource.python
it-python-plugin
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
python-custom-rules-plugin
diff --git a/its/pom.xml b/its/pom.xml
index 57b0b6e135..f589fa5b52 100644
--- a/its/pom.xml
+++ b/its/pom.xml
@@ -5,7 +5,7 @@
org.sonarsource.python
python
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
python-its
diff --git a/its/ruling/pom.xml b/its/ruling/pom.xml
index 14d816e5cf..5f516c15e0 100644
--- a/its/ruling/pom.xml
+++ b/its/ruling/pom.xml
@@ -6,7 +6,7 @@
org.sonarsource.python
python-its
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
it-python-ruling
diff --git a/pom.xml b/pom.xml
index d049358c7f..272adf6762 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
org.sonarsource.python
python
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
pom
Python
diff --git a/python-checks-testkit/pom.xml b/python-checks-testkit/pom.xml
index f9cda17797..98d409c671 100644
--- a/python-checks-testkit/pom.xml
+++ b/python-checks-testkit/pom.xml
@@ -6,7 +6,7 @@
python
org.sonarsource.python
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
python-checks-testkit
diff --git a/python-checks/pom.xml b/python-checks/pom.xml
index 3b144b7d24..60c6c9d6b5 100644
--- a/python-checks/pom.xml
+++ b/python-checks/pom.xml
@@ -5,7 +5,7 @@
org.sonarsource.python
python
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
python-checks
diff --git a/python-frontend/pom.xml b/python-frontend/pom.xml
index 5055a93e36..096195fe6b 100644
--- a/python-frontend/pom.xml
+++ b/python-frontend/pom.xml
@@ -5,7 +5,7 @@
org.sonarsource.python
python
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
python-frontend
diff --git a/sonar-python-plugin/pom.xml b/sonar-python-plugin/pom.xml
index bc4c38f7a1..81d8bcfc4b 100644
--- a/sonar-python-plugin/pom.xml
+++ b/sonar-python-plugin/pom.xml
@@ -5,7 +5,7 @@
org.sonarsource.python
python
- 2.14-SNAPSHOT
+ 3.0-SNAPSHOT
sonar-python-plugin
From 5bd36987282330ff829ed9a33d3c64610955028a Mon Sep 17 00:00:00 2001
From: Guillaume Dequenne
Date: Tue, 7 Jul 2020 10:23:58 +0200
Subject: [PATCH 2/5] SONARPY-748 Drop Pylint execution mode and old style
issue importing (#807)
---
.../com/sonar/python/it/plugin/Tests.java | 1 -
.../sonar/plugins/python/PythonPlugin.java | 40 ---
.../python/pylint/CommandStreamConsumer.java | 38 ---
.../sonar/plugins/python/pylint/Issue.java | 62 ----
.../python/pylint/PylintArguments.java | 63 ----
.../python/pylint/PylintConfiguration.java | 59 ----
.../python/pylint/PylintImportSensor.java | 147 ---------
.../python/pylint/PylintIssuesAnalyzer.java | 115 -------
.../python/pylint/PylintReportParser.java | 114 -------
.../python/pylint/PylintRuleParser.java | 73 -----
.../python/pylint/PylintRuleRepository.java | 78 -----
.../plugins/python/pylint/PylintSensor.java | 137 --------
.../plugins/python/PythonPluginTest.java | 2 +-
.../python/pylint/PylintArgumentsTest.java | 60 ----
.../pylint/PylintConfigurationTest.java | 66 ----
.../python/pylint/PylintImportSensorTest.java | 144 --------
.../python/pylint/PylintIssuesAnalyzerIT.java | 50 ---
.../pylint/PylintIssuesAnalyzerTest.java | 170 ----------
.../python/pylint/PylintRuleParserTest.java | 60 ----
.../pylint/PylintRuleRepositoryTest.java | 53 ---
.../python/pylint/PylintSensorTest.java | 212 ------------
.../org/sonar/plugins/python/pylint/empty.xml | 3 -
.../sonar/plugins/python/pylint/executable | 0
.../plugins/python/pylint/pylintrc_sample | 309 ------------------
24 files changed, 1 insertion(+), 2055 deletions(-)
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/CommandStreamConsumer.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/Issue.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintArguments.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintConfiguration.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintImportSensor.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzer.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintReportParser.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRuleParser.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRuleRepository.java
delete mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
delete mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintArgumentsTest.java
delete mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintConfigurationTest.java
delete mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintImportSensorTest.java
delete mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzerIT.java
delete mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzerTest.java
delete mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRuleParserTest.java
delete mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRuleRepositoryTest.java
delete mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/empty.xml
delete mode 100755 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/executable
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylintrc_sample
diff --git a/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/Tests.java b/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/Tests.java
index e8c6c64592..62278cf0fa 100644
--- a/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/Tests.java
+++ b/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/Tests.java
@@ -50,7 +50,6 @@
MetricsTest.class,
CPDTest.class,
CoverageTest.class,
- PylintReportTest.class,
TestReportTest.class,
NoSonarTest.class,
SonarLintTest.class
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java
index a6074b66af..c2ccfd1613 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java
@@ -31,10 +31,6 @@
import org.sonar.plugins.python.coverage.PythonCoverageSensor;
import org.sonar.plugins.python.flake8.Flake8RulesDefinition;
import org.sonar.plugins.python.flake8.Flake8Sensor;
-import org.sonar.plugins.python.pylint.PylintConfiguration;
-import org.sonar.plugins.python.pylint.PylintImportSensor;
-import org.sonar.plugins.python.pylint.PylintRuleRepository;
-import org.sonar.plugins.python.pylint.PylintSensor;
import org.sonar.plugins.python.warnings.DefaultAnalysisWarningsWrapper;
import org.sonar.plugins.python.xunit.PythonXUnitSensor;
@@ -79,7 +75,6 @@ public void define(Context context) {
context.addExtension(DefaultAnalysisWarningsWrapper.class);
addCoberturaExtensions(context);
addXUnitExtensions(context);
- addPylintExtensions(context);
addBanditExtensions(context);
addFlake8Extensions(context);
}
@@ -136,41 +131,6 @@ private static void addXUnitExtensions(Context context) {
PythonXUnitSensor.class);
}
- private static void addPylintExtensions(Context context) {
- context.addExtensions(
- PropertyDefinition.builder(PylintConfiguration.PYLINT_CONFIG_KEY)
- .index(30)
- .name("Pylint configuration")
- .description("Path to the pylint configuration file to use in pylint analysis. Set to empty to use the default.")
- .category(PYTHON_CATEGORY)
- .subCategory(PYLINT)
- .onQualifiers(Qualifiers.PROJECT)
- .defaultValue("")
- .build(),
- PropertyDefinition.builder(PylintConfiguration.PYLINT_KEY)
- .index(31)
- .name("Pylint executable")
- .description("Path to the pylint executable to use in pylint analysis. Set to empty to use the default one.")
- .category(PYTHON_CATEGORY)
- .subCategory(PYLINT)
- .onQualifiers(Qualifiers.PROJECT)
- .defaultValue("")
- .build(),
- PropertyDefinition.builder(PylintImportSensor.REPORT_PATH_KEY)
- .index(32)
- .name("Pylint's reports")
- .description("Path to Pylint's report file, relative to projects root")
- .category(PYTHON_CATEGORY)
- .subCategory(PYLINT)
- .onQualifiers(Qualifiers.PROJECT)
- .defaultValue("")
- .build(),
- PylintConfiguration.class,
- PylintSensor.class,
- PylintImportSensor.class,
- PylintRuleRepository.class);
- }
-
private static void addBanditExtensions(Context context) {
context.addExtension(BanditSensor.class);
boolean externalIssuesSupported = context.getSonarQubeVersion().isGreaterThanOrEqual(Version.create(7, 2));
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/CommandStreamConsumer.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/CommandStreamConsumer.java
deleted file mode 100644
index b43a9bb1dc..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/CommandStreamConsumer.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import org.sonar.api.utils.command.StreamConsumer;
-
-import java.util.LinkedList;
-import java.util.List;
-
-class CommandStreamConsumer implements StreamConsumer {
- private List data = new LinkedList<>();
-
- @Override
- public void consumeLine(String line) {
- data.add(line);
- }
-
- public List getData() {
- return data;
- }
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/Issue.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/Issue.java
deleted file mode 100644
index ffc98db8ef..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/Issue.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-class Issue {
-
- private final String filename;
- private final int line;
- private final String ruleId;
- private final String objname;
- private final String descr;
-
- Issue(String filename, int line, String ruleId, String objname, String descr) {
- this.filename = filename;
- this.line = line;
- this.ruleId = ruleId;
- this.objname = objname;
- this.descr = descr;
- }
-
- @Override
- public String toString() {
- return "(" + filename + ", " + line + ", " + ruleId + ", " + objname + ", " + descr + ")";
- }
-
- String getFilename() {
- return filename;
- }
-
- int getLine() {
- return line;
- }
-
- String getRuleId() {
- return ruleId;
- }
-
- String getObjName() {
- return objname;
- }
-
- String getDescription() {
- return descr;
- }
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintArguments.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintArguments.java
deleted file mode 100644
index 647461c207..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintArguments.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Stream;
-import org.sonar.api.utils.command.Command;
-import org.sonar.api.utils.command.CommandExecutor;
-
-public class PylintArguments {
-
- private static final Pattern PYLINT_VERSION_PATTERN = Pattern.compile(".*pylint[^ ]* ([0-9\\.]+).*");
- private static final String[] ARGS_PYLINT_0_X = {"-i", "y", "-f", "parseable", "-r", "n"};
- private static final String[] ARGS_PYLINT_1_X = {"--msg-template", "{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}", "-r", "n"};
-
- private final String[] arguments;
-
- public PylintArguments(Command command) {
- String pylintVersion = pylintVersion(command);
- this.arguments = pylintVersion.startsWith("0") ? ARGS_PYLINT_0_X : ARGS_PYLINT_1_X;
- }
-
- private static String pylintVersion(Command command) {
- long timeout = 10_000;
- CommandStreamConsumer out = new CommandStreamConsumer();
- CommandStreamConsumer err = new CommandStreamConsumer();
- CommandExecutor.create().execute(command, out, err, timeout);
- Stream outputLines = Stream.concat(out.getData().stream(), err.getData().stream());
-
- for (String outLine : (Iterable) outputLines::iterator) {
- Matcher matcher = PYLINT_VERSION_PATTERN.matcher(outLine);
- if (matcher.matches()) {
- return matcher.group(1);
- }
- }
- String message = String.format("Failed to determine pylint version with command: \"%s\", received %d line(s) of output:%n%s",
- command.toCommandLine(), out.getData().size() + err.getData().size(), out.getData() + "\n" + err.getData());
- throw new IllegalArgumentException(message);
- }
-
- public String[] arguments() {
- return arguments;
- }
-
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintConfiguration.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintConfiguration.java
deleted file mode 100644
index 7ab346f910..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintConfiguration.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.io.File;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.ExtensionPoint;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.config.Configuration;
-
-@ScannerSide
-@ExtensionPoint
-public class PylintConfiguration {
-
- public static final String PYLINT_CONFIG_KEY = "sonar.python.pylint_config";
- public static final String PYLINT_KEY = "sonar.python.pylint";
-
- private final Configuration conf;
-
- public PylintConfiguration(Configuration conf) {
- this.conf = conf;
- }
-
- public String getPylintConfigPath(FileSystem fileSystem) {
- String configPath = conf.get(PylintConfiguration.PYLINT_CONFIG_KEY).orElse("");
- if (StringUtils.isEmpty(configPath)) {
- return null;
- }
- File configFile = new File(configPath);
- if (!configFile.isAbsolute()) {
- File projectRoot = fileSystem.baseDir();
- configFile = new File(projectRoot.getPath(), configPath);
- }
- return configFile.getAbsolutePath();
- }
-
- public String getPylintPath() {
- return conf.get(PylintConfiguration.PYLINT_KEY).orElse(null);
- }
-
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintImportSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintImportSensor.java
deleted file mode 100644
index 698f84d511..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintImportSensor.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Scanner;
-import java.util.Set;
-import javax.annotation.Nullable;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.rule.ActiveRule;
-import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.api.batch.sensor.issue.NewIssue;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.plugins.python.PythonReportSensor;
-import org.sonar.plugins.python.warnings.AnalysisWarningsWrapper;
-
-public class PylintImportSensor extends PythonReportSensor {
- public static final String REPORT_PATH_KEY = "sonar.python.pylint.reportPath";
- private static final String DEFAULT_REPORT_PATH = "pylint-reports/pylint-result-*.txt";
-
- private static final Logger LOG = Loggers.get(PylintImportSensor.class);
- private static final PylintRuleParser pylintRules = new PylintRuleParser(PylintRuleRepository.RULES_FILE);
- private static final Set warningAlreadyLogged = new HashSet<>();
-
- public PylintImportSensor(Configuration conf, AnalysisWarningsWrapper analysisWarnings) {
- super(conf, analysisWarnings, "Pylint");
- }
-
- @Override
- public void describe(SensorDescriptor descriptor) {
- super.describe(descriptor);
- descriptor
- .createIssuesForRuleRepository(PylintRuleRepository.REPOSITORY_KEY)
- .onlyWhenConfiguration(conf -> conf.hasKey(REPORT_PATH_KEY));
- }
-
- @Override
- protected String reportPathKey() {
- return REPORT_PATH_KEY;
- }
-
- @Override
- protected String defaultReportPath() {
- return DEFAULT_REPORT_PATH;
- }
-
- @Override
- protected void processReports(final SensorContext context, List reports) {
- List issues = new LinkedList<>();
- for (File report : reports) {
- try {
- issues.addAll(parse(report, context.fileSystem()));
- } catch (java.io.FileNotFoundException e) {
- LOG.error("Report '{}' cannot be found, details: '{}'", report, e);
- } catch (IOException e) {
- LOG.error("Report '{}' cannot be read, details: '{}'", report, e);
- }
- }
-
- saveIssues(issues, context);
- }
-
- private static List parse(File report, FileSystem fileSystem) throws IOException {
- List issues = new LinkedList<>();
-
- PylintReportParser parser = new PylintReportParser();
- Scanner sc;
- for (sc = new Scanner(report.toPath(), fileSystem.encoding().name()); sc.hasNext(); ) {
- String line = sc.nextLine();
- Issue issue = parser.parseLine(line);
- if (issue != null) {
- issues.add(issue);
- }
- }
- sc.close();
- return issues;
- }
-
- private static void saveIssues(List issues, SensorContext context) {
- FileSystem fileSystem = context.fileSystem();
- for (Issue pylintIssue : issues) {
- String filepath = pylintIssue.getFilename();
- InputFile pyfile = fileSystem.inputFile(fileSystem.predicates().hasPath(filepath));
- if (pyfile != null) {
- ActiveRule rule = context.activeRules().find(RuleKey.of(PylintRuleRepository.REPOSITORY_KEY, pylintIssue.getRuleId()));
- processRule(pylintIssue, pyfile, rule, context);
- } else {
- LOG.warn("Cannot find the file '{}' in SonarQube, ignoring violation", filepath);
- }
- }
- }
-
- public static void processRule(Issue pylintIssue, InputFile pyfile, @Nullable ActiveRule rule, SensorContext context) {
- if (rule != null) {
- NewIssue newIssue = context
- .newIssue()
- .forRule(rule.ruleKey());
- newIssue.at(
- newIssue.newLocation()
- .on(pyfile)
- .at(pyfile.selectLine(pylintIssue.getLine()))
- .message(pylintIssue.getDescription()));
- newIssue.save();
- } else if (!pylintRules.hasRuleDefinition(pylintIssue.getRuleId())) {
- logUnknownRuleWarning(pylintIssue.getRuleId());
- }
- }
-
- private static void logUnknownRuleWarning(String ruleId) {
- if (!warningAlreadyLogged.contains(ruleId)) {
- warningAlreadyLogged.add(ruleId);
- LOG.warn("Pylint rule '{}' is unknown in Sonar", ruleId);
- }
- }
-
- // Visible for testing
- static void clearLoggedWarnings() {
- warningAlreadyLogged.clear();
- }
-
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzer.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzer.java
deleted file mode 100644
index 6b3bba4414..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzer.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.util.LinkedList;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.utils.command.Command;
-import org.sonar.api.utils.command.CommandExecutor;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-public class PylintIssuesAnalyzer {
-
- private static final Logger LOG = Loggers.get(PylintIssuesAnalyzer.class);
-
- private static final String FALLBACK_PYLINT = "pylint";
-
- private String pylint = null;
- private String pylintConfigParam = null;
- private PylintArguments pylintArguments;
-
- PylintIssuesAnalyzer(String pylintPath, String pylintConfigPath) {
- this(pylintPath, pylintConfigPath, new PylintArguments(Command.create(pylintPathWithDefault(pylintPath)).addArgument("--version")));
- }
-
- PylintIssuesAnalyzer(String pylintPath, @Nullable String pylintConfigPath, PylintArguments arguments) {
- pylint = pylintPathWithDefault(pylintPath);
-
- if (pylintConfigPath != null) {
- if (!new File(pylintConfigPath).exists()) {
- throw new IllegalStateException("Cannot find the pylint configuration file: " + pylintConfigPath);
- }
- pylintConfigParam = "--rcfile=" + pylintConfigPath;
- }
-
- pylintArguments = arguments;
- }
-
- private static String pylintPathWithDefault(@Nullable String pylintPath) {
- if (pylintPath != null) {
- if (!new File(pylintPath).exists()) {
- throw new IllegalStateException("Cannot find the pylint executable: " + pylintPath);
- }
- return pylintPath;
- }
- return FALLBACK_PYLINT;
- }
-
- public List analyze(String path, Charset charset, File out) throws IOException {
- Command command = Command.create(pylint).addArguments(pylintArguments.arguments()).addArgument(path);
-
- if (pylintConfigParam != null) {
- command.addArgument(pylintConfigParam);
- }
-
- LOG.debug("Calling command: '{}'", command);
-
- long timeoutMS = 300_000; // =5min
- CommandStreamConsumer stdOut = new CommandStreamConsumer();
- CommandStreamConsumer stdErr = new CommandStreamConsumer();
- CommandExecutor.create().execute(command, stdOut, stdErr, timeoutMS);
-
- // the error stream can contain a line like 'no custom config found, using default'
- // any bigger output on the error stream is likely a pylint malfunction
- if (stdErr.getData().size() > 1) {
- LOG.warn("Output on the error channel detected: this is probably due to a problem on pylint's side.");
- String data = StringUtils.join(stdErr.getData(), "\n");
- LOG.warn("Content of the error stream: \n\"{}\"", data);
- }
-
- String str = StringUtils.join(stdOut.getData(), "\n");
- Files.write(out.toPath(), str.getBytes(charset));
-
- return parseOutput(stdOut.getData());
- }
-
- protected List parseOutput(List lines) {
- List issues = new LinkedList<>();
-
- PylintReportParser parser = new PylintReportParser();
- if (!lines.isEmpty()) {
- for (String line : lines) {
- Issue issue = parser.parseLine(line);
- if (issue != null) {
- issues.add(issue);
- }
- }
- }
-
- return issues;
- }
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintReportParser.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintReportParser.java
deleted file mode 100644
index 0df734efbc..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintReportParser.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-public class PylintReportParser {
- private static final Pattern PATTERN = Pattern.compile("(.+):([0-9]+): \\[(.*)\\] (.*)");
- private static final Logger LOG = Loggers.get(PylintReportParser.class);
-
- // Pylint 0.24 brings a nasty reidentifying of some rules...
- // To avoid burdening of users with rule clones we map the ids.
- // This workaround can die as soon as pylints <= 0.23.X become obsolete.
- private static final Map ID_MAP = initializeIdMap();
-
- private static Map initializeIdMap() {
- Map map = new HashMap<>();
- map.put("E9900", "E1300");
- map.put("E9901", "E1301");
- map.put("E9902", "E1302");
- map.put("E9903", "E1303");
- map.put("E9904", "E1304");
- map.put("E9905", "E1305");
- map.put("E9906", "E1306");
- map.put("W6501", "W1201");
- map.put("W9900", "W1300");
- map.put("W9901", "W1301");
- return Collections.unmodifiableMap(map);
- }
-
- public Issue parseLine(String line) {
- // Parse the output of pylint. Example of the format:
- //
- // complexity/code_chunks.py:62: [W0104, list_compr] Statement seems to have no effect
- // complexity/code_chunks.py:64: [C0111, list_compr_filter] Missing docstring
- // ...
-
- Issue issue = null;
-
- int linenr;
- String ruleid;
- String objname;
- String descr;
- String filename;
-
- if (line.length() > 0) {
- if (!isDetail(line)) {
- Matcher m = PATTERN.matcher(line);
- if (m.matches() && m.groupCount() == 4) {
- filename = m.group(1);
- linenr = Integer.valueOf(m.group(2));
- String[] parts = m.group(3).split(",");
-
- ruleid = ruleId(parts[0].trim());
-
- if (parts.length == 2) {
- objname = parts[1].trim();
- } else {
- objname = "";
- }
-
- descr = m.group(4);
- issue = new Issue(filename, linenr, ruleid, objname, descr);
- } else {
- LOG.debug("Cannot parse the line: {}", line);
- }
- } else {
- LOG.trace("Classifying as detail and ignoring line '{}'", line);
- }
- }
-
- return issue;
- }
-
- private static String ruleId(String ruleAndMessageIds) {
- String ruleid = ruleAndMessageIds;
- int parenthesisIndex = ruleid.indexOf('(');
- if (parenthesisIndex > -1) {
- ruleid = ruleid.substring(0, parenthesisIndex);
- }
- if (ID_MAP.containsKey(ruleid)) {
- ruleid = ID_MAP.get(ruleid);
- }
- return ruleid;
- }
-
- private static boolean isDetail(String line) {
- char first = line.charAt(0);
- return first == ' ' || first == '\t' || first == '\n';
- }
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRuleParser.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRuleParser.java
deleted file mode 100644
index efe5f8881e..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRuleParser.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashSet;
-import java.util.Set;
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.XMLEvent;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonarsource.analyzer.commons.xml.SafetyFactory;
-
-public class PylintRuleParser {
-
- private static final Logger LOG = Loggers.get(PylintRuleParser.class);
- private Set definedRulesId = new HashSet<>();
- private StringBuilder currentKey = new StringBuilder();
-
- public PylintRuleParser(String rulesPath) {
- try (InputStream inputStream = getClass().getResourceAsStream(rulesPath)) {
- XMLEventReader reader = SafetyFactory.createXMLInputFactory().createXMLEventReader(inputStream);
- while (reader.hasNext()) {
- onXmlEvent(reader.nextEvent());
- }
- } catch (IOException | XMLStreamException | IllegalArgumentException e) {
- LOG.warn("Unable to parse the Pylint rules definition XML file");
- }
-
- if (definedRulesId.isEmpty()) {
- LOG.warn("No rule key found for Pylint");
- }
- }
-
- private void onXmlEvent(XMLEvent event) {
- if (event.isStartElement()) {
- StartElement element = event.asStartElement();
- String elementName = element.getName().getLocalPart();
- if ("key".equals(elementName)) {
- currentKey = new StringBuilder();
- }
- } else if (event.isCharacters()) {
- currentKey.append(event.asCharacters().getData());
- } else if (event.isEndElement() && "key".equals(event.asEndElement().getName().getLocalPart())) {
- definedRulesId.add(currentKey.toString());
- }
- }
-
- public boolean hasRuleDefinition(String ruleId) {
- return definedRulesId.contains(ruleId);
- }
-
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRuleRepository.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRuleRepository.java
deleted file mode 100644
index f91cd9bffd..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRuleRepository.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Scanner;
-import org.sonar.api.server.rule.RulesDefinition;
-import org.sonar.api.server.rule.RulesDefinitionXmlLoader;
-import org.sonar.plugins.python.Python;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-public class PylintRuleRepository implements RulesDefinition {
-
- public static final String REPOSITORY_NAME = "Pylint";
- public static final String REPOSITORY_KEY = REPOSITORY_NAME;
-
- public static final String RULES_FILE = "/org/sonar/plugins/python/pylint/rules.xml";
- private static final String REMEDIATION_FILE = "/org/sonar/plugins/python/pylint/remediation-cost.csv";
-
- private final RulesDefinitionXmlLoader xmlLoader;
-
- public PylintRuleRepository(RulesDefinitionXmlLoader xmlLoader) {
- this.xmlLoader = xmlLoader;
- }
-
- @Override
- public void define(Context context) {
- NewRepository repository = context
- .createRepository(REPOSITORY_KEY, Python.KEY)
- .setName(REPOSITORY_NAME);
- xmlLoader.load(repository, getClass().getResourceAsStream(RULES_FILE), UTF_8.name());
- defineRemediationFunction(repository);
- repository.done();
- }
-
- private static void defineRemediationFunction(NewRepository repository) {
- Map remediationCostMap = loadRemediationCostMap();
- for (NewRule rule : repository.rules()) {
- String gap = remediationCostMap.get(rule.key());
- if (gap == null) {
- throw new IllegalStateException("Missing remediation cost for rule " + rule.key());
- } else if (!gap.equals("null")) {
- rule.setDebtRemediationFunction(rule.debtRemediationFunctions().linear(gap));
- }
- }
- }
-
- private static Map loadRemediationCostMap() {
- Map map = new HashMap<>();
- try (Scanner scanner = new Scanner(PylintRuleRepository.class.getResourceAsStream(REMEDIATION_FILE), UTF_8.name())) {
- while (scanner.hasNext()) {
- String[] cols = scanner.next().split(",");
- map.put(cols[0], cols[1]);
- }
- }
- return map;
- }
-
-}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
deleted file mode 100644
index 5852d17941..0000000000
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.sonar.api.batch.fs.FilePredicates;
-import org.sonar.api.batch.fs.FileSystem;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.rule.ActiveRule;
-import org.sonar.api.batch.sensor.Sensor;
-import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.batch.sensor.SensorDescriptor;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.notifications.AnalysisWarnings;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.plugins.python.Python;
-
-public class PylintSensor implements Sensor {
-
- private static final Logger LOG = Loggers.get(PylintSensor.class);
-
- private final PylintConfiguration conf;
- private final Configuration settings;
- private PylintIssuesAnalyzer analyzer;
- private final AnalysisWarnings analysisWarnings;
-
- public PylintSensor(PylintConfiguration conf, Configuration settings, AnalysisWarnings analysisWarnings) {
- this.conf = conf;
- this.settings = settings;
- this.analysisWarnings = analysisWarnings;
- }
-
- @Override
- public void describe(SensorDescriptor descriptor) {
- descriptor
- .name("PylintSensor")
- .onlyOnLanguage(Python.KEY)
- .onlyOnFileType(InputFile.Type.MAIN)
- .createIssuesForRuleRepository(PylintRuleRepository.REPOSITORY_KEY);
- }
-
- boolean shouldExecute() {
- return !settings.get(PylintImportSensor.REPORT_PATH_KEY).isPresent();
- }
-
- @Override
- public void execute(SensorContext sensorContext) {
- File workDir = new File(sensorContext.fileSystem().workDir(), "pylint");
- if (!sensorContext.activeRules().findByRepository("Pylint").isEmpty()) {
- analysisWarnings.addUnique("Deprecation notice and future breaking changes: The import of Pylint issues will soon change. " +
- "Please follow the instructions in documentation’s section \"Analyzing Source Code\" >> \"Languages\" >> \"Python\" >> \"Pylint\".");
- }
- if (!shouldExecute() || !prepareWorkDir(workDir) || !initializeAnalyzer(sensorContext)) {
- return;
- }
-
- LOG.warn("Execution of Pylint is deprecated and will be removed." +
- " Instead, Pylint should be executed before sonar-scanner and its report should be imported using the '" + PylintImportSensor.REPORT_PATH_KEY + "' property.");
-
- int i = 0;
- FileSystem fileSystem = sensorContext.fileSystem();
- FilePredicates p = fileSystem.predicates();
- Iterable files = fileSystem.inputFiles(p.and(p.hasType(InputFile.Type.MAIN), p.hasLanguage(Python.KEY)));
- for (InputFile file : files) {
- try {
- File out = new File(workDir, i + ".out");
- analyzeFile(sensorContext, file, out);
- i++;
- } catch (Exception e) {
- LOG.warn("Cannot analyse file '{}', the following exception occurred:", file.toString(), e);
- }
- }
- }
-
- private boolean initializeAnalyzer(SensorContext context) {
- try {
- String pylintConfigPath = conf.getPylintConfigPath(context.fileSystem());
- String pylintPath = conf.getPylintPath();
- analyzer = createAnalyzer(pylintConfigPath, pylintPath);
- return true;
- } catch (Exception e) {
- LOG.warn("Unable to use pylint for analysis. Error:", e);
- return false;
- }
- }
-
- // Visible for testing
- PylintIssuesAnalyzer createAnalyzer(String pylintConfigPath, String pylintPath) {
- return new PylintIssuesAnalyzer(pylintPath, pylintConfigPath);
- }
-
- private void analyzeFile(SensorContext context, InputFile file, File out) throws IOException {
- FileSystem fileSystem = context.fileSystem();
-
- List issues = analyzer.analyze(file.absolutePath(), fileSystem.encoding(), out);
-
- for (Issue pylintIssue : issues) {
- ActiveRule rule = context.activeRules().find(RuleKey.of(PylintRuleRepository.REPOSITORY_KEY, pylintIssue.getRuleId()));
- PylintImportSensor.processRule(pylintIssue, file, rule, context);
- }
- }
-
- private static boolean prepareWorkDir(File dir) {
- try {
- FileUtils.forceMkdir(dir);
- // directory is cleaned, because Sonar 3.0 will not do this for us
- FileUtils.cleanDirectory(dir);
- return true;
- } catch (IOException e) {
- LOG.warn("Cannot create directory '{}'. Error:", dir, e);
- return false;
- }
- }
-
-}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java
index 2a1a882333..ef92e93ff1 100644
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java
+++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java
@@ -37,7 +37,7 @@ public class PythonPluginTest {
public void testGetExtensions() {
Version v74 = Version.create(7, 9);
SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(v74, SonarQubeSide.SERVER, SonarEdition.DEVELOPER);
- assertThat(extensions(runtime)).hasSize(25);
+ assertThat(extensions(runtime)).hasSize(18);
assertThat(extensions(runtime)).contains(DefaultAnalysisWarningsWrapper.class);
assertThat(extensions(SonarRuntimeImpl.forSonarLint(v74))).hasSize(5);
}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintArgumentsTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintArgumentsTest.java
deleted file mode 100644
index f9aa457089..0000000000
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintArgumentsTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import org.apache.commons.lang.SystemUtils;
-import org.junit.Test;
-import org.sonar.api.utils.command.Command;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PylintArgumentsTest {
-
- @Test
- public void pylint_0_x() {
- String[] arguments = new PylintArguments(command("pylint 0.28.0")).arguments();
- assertThat(arguments).containsOnly("-i", "y", "-f", "parseable", "-r", "n");
- }
-
- @Test
- public void pylint_bat_0_x() {
- String[] arguments = new PylintArguments(command("pylint.bat 0.28.0")).arguments();
- assertThat(arguments).containsOnly("-i", "y", "-f", "parseable", "-r", "n");
- }
-
- @Test
- public void pylint_1_x() {
- String[] arguments = new PylintArguments(command("pylint 1.1.0")).arguments();
- assertThat(arguments).containsOnly("--msg-template", "{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}", "-r", "n");
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void unknown() {
- new PylintArguments(command(""));
- }
-
- private static Command command(String toOutput) {
- if (SystemUtils.IS_OS_WINDOWS) {
- return Command.create("cmd.exe").addArguments(new String[] {"/c", "echo", toOutput});
- }
- return Command.create("echo").addArgument(toOutput);
- }
-
-}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintConfigurationTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintConfigurationTest.java
deleted file mode 100644
index dc808e3a08..0000000000
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintConfigurationTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.io.File;
-import org.junit.Before;
-import org.junit.Test;
-import org.sonar.api.batch.fs.internal.DefaultFileSystem;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PylintConfigurationTest {
-
- private MapSettings settings;
- private PylintConfiguration pylintConfiguration;
-
- @Before
- public void setUp() {
- settings = new MapSettings();
- pylintConfiguration = new PylintConfiguration(new ConfigurationBridge(settings));
- }
-
- @Test
- public void shouldGetCorrectPylintPath() {
- DefaultFileSystem fs = new DefaultFileSystem(new File("").getAbsoluteFile());
-
- assertThat(pylintConfiguration.getPylintConfigPath(fs)).isNull();
-
- settings.setProperty(PylintConfiguration.PYLINT_CONFIG_KEY, (String) null);
- assertThat(pylintConfiguration.getPylintConfigPath(fs)).isNull();
-
- settings.setProperty(PylintConfiguration.PYLINT_CONFIG_KEY, ".pylintrc");
- assertThat(pylintConfiguration.getPylintConfigPath(fs)).isEqualTo(new File(".pylintrc").getAbsolutePath());
-
- String absolutePath = new File("/absolute/.pylintrc").getAbsolutePath();
- settings.setProperty(PylintConfiguration.PYLINT_CONFIG_KEY, absolutePath);
- assertThat(pylintConfiguration.getPylintConfigPath(fs)).isEqualTo(absolutePath);
- }
-
- @Test
- public void getPylintPath() {
- String path = "test/path";
- settings.setProperty(PylintConfiguration.PYLINT_KEY, path);
-
- assertThat(pylintConfiguration.getPylintPath()).isEqualTo(path);
- }
-}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintImportSensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintImportSensorTest.java
deleted file mode 100644
index ad6e25b75f..0000000000
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintImportSensorTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import com.google.common.collect.ImmutableMap;
-import java.io.File;
-import java.nio.charset.StandardCharsets;
-import java.util.Map;
-import java.util.function.Predicate;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
-import org.sonar.api.batch.rule.internal.NewActiveRule;
-import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
-import org.sonar.api.batch.sensor.internal.SensorContextTester;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.plugins.python.Python;
-import org.sonar.plugins.python.TestUtils;
-import org.sonar.plugins.python.warnings.AnalysisWarningsWrapper;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.spy;
-
-public class PylintImportSensorTest {
-
- public static final String FILE1_PATH = "src/file1.py";
- public static final String RULE_C0103 = "C0103";
- public static final String RULE_C0111 = "C0111";
- private final File baseDir = new File("src/test/resources/org/sonar/plugins/python/pylint");
- private final SensorContextTester context = SensorContextTester.create(baseDir);
- private final AnalysisWarningsWrapper analysisWarnings = spy(AnalysisWarningsWrapper.class);
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Test
- public void parse_report() {
- context.settings().setProperty(PylintImportSensor.REPORT_PATH_KEY, "pylint-report.txt");
-
- File file = new File(baseDir, FILE1_PATH);
- DefaultInputFile inputFile = TestInputFileBuilder.create("", FILE1_PATH)
- .setLanguage(Python.KEY)
- .initMetadata(TestUtils.fileContent(file, StandardCharsets.UTF_8))
- .build();
- context.fileSystem().add(inputFile);
-
- context.setActiveRules(
- new ActiveRulesBuilder()
- .addRule(new NewActiveRule.Builder()
- .setRuleKey(RuleKey.of(PylintRuleRepository.REPOSITORY_KEY, RULE_C0103))
- .setName("Invalid name")
- .build())
- .addRule(new NewActiveRule.Builder()
- .setRuleKey(RuleKey.of(PylintRuleRepository.REPOSITORY_KEY, RULE_C0111))
- .setName("Missing docstring")
- .build())
- .build());
-
- PylintImportSensor sensor = new PylintImportSensor(context.config(), analysisWarnings);
- sensor.execute(context);
- assertThat(context.allIssues()).hasSize(3);
- assertThat(context.allIssues()).extracting(issue -> issue.primaryLocation().inputComponent().key())
- .containsOnly(inputFile.key());
- }
-
- @Test
- public void logsOnlyUnknownRules () {
- context.settings().setProperty(PylintImportSensor.REPORT_PATH_KEY, "pylint-report-unknown-rules.txt");
-
- File file = new File(baseDir, FILE1_PATH);
- DefaultInputFile inputFile = TestInputFileBuilder.create("", FILE1_PATH)
- .setLanguage(Python.KEY)
- .initMetadata(TestUtils.fileContent(file, StandardCharsets.UTF_8))
- .build();
- context.fileSystem().add(inputFile);
-
- context.setActiveRules(
- new ActiveRulesBuilder()
- .addRule(new NewActiveRule.Builder()
- .setRuleKey(RuleKey.of(PylintRuleRepository.REPOSITORY_KEY, RULE_C0103))
- .setName("Invalid name")
- .build())
- .build());
-
- PylintImportSensor sensor = new PylintImportSensor(context.config(), analysisWarnings);
- PylintImportSensor.clearLoggedWarnings();
- sensor.execute(context);
- assertThat(context.allIssues()).hasSize(1);
- assertThat(context.allIssues()).extracting(issue -> issue.primaryLocation().inputComponent().key()).containsOnly(inputFile.key());
- assertThat(context.allIssues()).extracting(issue -> issue.ruleKey().rule()).containsExactly(RULE_C0103);
- assertThat(logTester.logs(LoggerLevel.WARN)).containsExactly("Pylint rule 'C8888' is unknown in Sonar", "Pylint rule 'C9999' is unknown in Sonar");
- }
-
- @Test
- public void sensor_descriptor() {
- DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
- new PylintImportSensor(context.config(), analysisWarnings).describe(descriptor);
- assertThat(descriptor.name()).isEqualTo("PylintImportSensor");
- assertThat(descriptor.languages()).containsOnly("py");
- assertThat(descriptor.type()).isEqualTo(InputFile.Type.MAIN);
- assertThat(descriptor.ruleRepositories()).containsExactly(PylintRuleRepository.REPOSITORY_KEY);
- Predicate configurationPredicate = descriptor.configurationPredicate();
- assertThat(configurationPredicate.test(configuration(ImmutableMap.of(PylintImportSensor.REPORT_PATH_KEY, "something")))).isTrue();
- assertThat(configurationPredicate.test(configuration(ImmutableMap.of("xxx", "yyy")))).isFalse();
- }
-
- @Test
- public void no_default_report_log() {
- SensorContextTester defaultContext = SensorContextTester.create(baseDir);
- PylintImportSensor sensor = new PylintImportSensor(defaultContext.config(), analysisWarnings);
- sensor.execute(defaultContext);
- assertThat(logTester.logs(LoggerLevel.DEBUG)).contains("No report was found for sonar.python.pylint.reportPath using default pattern pylint-reports/pylint-result-*.txt");
- }
-
- private static Configuration configuration(Map mapproperties) {
- return new ConfigurationBridge(new MapSettings().addProperties(mapproperties));
- }
-
-}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzerIT.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzerIT.java
deleted file mode 100644
index 07fbbf7fa6..0000000000
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzerIT.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.nio.charset.StandardCharsets;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-import java.io.File;
-import java.util.List;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.plugins.python.pylint.PylintIssuesAnalyzerTest.RESOURCE_DIR;
-
-public class PylintIssuesAnalyzerIT {
-
- @Rule
- public TemporaryFolder tempFolder = new TemporaryFolder();
-
- @Test
- public void issuesTest() throws Exception {
- String pylintrcResource = RESOURCE_DIR + "/org/sonar/plugins/python/pylint/pylintrc_sample";
- String codeChunksResource = "/org/sonar/plugins/python/code_chunks_2.py";
- String codeChunksPathName = getClass().getResource(codeChunksResource).getPath();
- String pylintPath = null;
- File out = tempFolder.newFile();
-
- List issues = new PylintIssuesAnalyzer(pylintPath, pylintrcResource).analyze(codeChunksPathName, StandardCharsets.UTF_8, out);
- assertThat(issues).isNotEmpty();
- }
-
-}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzerTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzerTest.java
deleted file mode 100644
index 2ad17550d2..0000000000
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintIssuesAnalyzerTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-import org.junit.Test;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-
-public class PylintIssuesAnalyzerTest {
-
- private static final Logger LOG = Loggers.get(PylintIssuesAnalyzerTest.class);
- static final String RESOURCE_DIR = "src/test/resources";
-
- @Test
- public void shouldParseCorrectly() {
- String resourceName = "/org/sonar/plugins/python/pylint/sample_pylint_output.txt";
- String pylintConfigPath = null;
- String pylintPath = null;
- List lines = readFile(resourceName);
- List issues = analyzer(pylintPath, pylintConfigPath).parseOutput(lines);
- assertThat(issues.size()).isEqualTo(21);
- }
-
- @Test
- public void shouldParseCorrectlyNewFormat() {
- String resourceName = "/org/sonar/plugins/python/pylint/sample_pylint_output_new_format.txt";
- String pylintConfigPath = null;
- String pylintPath = null;
- List lines = readFile(resourceName);
- List issues = analyzer(pylintPath, pylintConfigPath).parseOutput(lines);
- assertThat(issues.size()).isEqualTo(1);
- assertThat(issues.get(0).getRuleId()).isEqualTo("C0111");
- }
-
- @Test
- public void shouldParseCorrectlyOutputWithWindowsPaths() {
- String resourceName = "/org/sonar/plugins/python/pylint/sample_pylint_output_with_win_paths.txt";
- String pylintConfigPath = null;
- String pylintPath = null;
- List lines = readFile(resourceName);
- List issues = analyzer(pylintPath, pylintConfigPath).parseOutput(lines);
- assertThat(issues.size()).isEqualTo(1);
- }
-
- @Test
- public void shouldMapIssuesIdsCorrectly() {
- String resourceOld = "/org/sonar/plugins/python/pylint/sample_pylint_output_oldids.txt";
- String resourceNew = "/org/sonar/plugins/python/pylint/sample_pylint_output_newids.txt";
- String pylintConfigPath = null;
- String pylintPath = null;
- List linesOld = readFile(resourceOld);
- List linesNew = readFile(resourceNew);
- List issuesOld = analyzer(pylintPath, pylintConfigPath).parseOutput(linesOld);
- List issuesNew = analyzer(pylintPath, pylintConfigPath).parseOutput(linesNew);
- assertThat(getIds(issuesOld)).isEqualTo(getIds(issuesNew));
- }
-
- @Test
- public void shouldWorkWithValidCustomConfig() {
- String resourceName = "/org/sonar/plugins/python/pylint/pylintrc_sample";
- String pylintConfigPath = getClass().getResource(resourceName).getPath();
- String pylintPath = null;
- analyzer(pylintPath, pylintConfigPath);
- }
-
- @Test(expected = IllegalStateException.class)
- public void shouldFailIfGivenInvalidConfig() {
- String pylintConfigPath = "xx_path_that_doesnt_exist_xx";
- String pylintPath = null;
- analyzer(pylintPath, pylintConfigPath);
- }
-
- @Test
- public void shouldInstantiateWhenGivenValidParams() {
- String pylintrcResource = "/org/sonar/plugins/python/pylint/pylintrc_sample";
- String pylintrcPath = getClass().getResource(pylintrcResource).getPath();
- String executableResource = "/org/sonar/plugins/python/pylint/executable";
- String executablePath = getClass().getResource(executableResource).getPath();
- final String[] validParameters =
- {
- null, null,
- executablePath, null,
- null, pylintrcPath,
- executablePath, pylintrcPath
- };
-
- int numberOfParams = validParameters.length;
- for(int i = 0; i readFile(String path) {
- try {
- return Files.readAllLines(Paths.get(RESOURCE_DIR, path), UTF_8);
- } catch (IOException e) {
- LOG.error("Cannot read the file '{}'", path);
- return Collections.emptyList();
- }
- }
-
- private static List getIds(List issues){
- List ids = new LinkedList<>();
- for(Issue issue: issues) {
- ids.add(issue.getRuleId());
- }
- return ids;
- }
-
- private static PylintIssuesAnalyzer analyzer(String pylintPath, String pylintConfigPath) {
- PylintArguments arguments = mock(PylintArguments.class);
- return new PylintIssuesAnalyzer(pylintPath, pylintConfigPath, arguments);
- }
-
-}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRuleParserTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRuleParserTest.java
deleted file mode 100644
index 8c201cd9fe..0000000000
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRuleParserTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.log.LogTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PylintRuleParserTest {
-
- private static final String NO_RULE_FOUND_MESSAGE = "No rule key found for Pylint";
-
- @Rule
- public LogTester logTester = new LogTester();
-
- @Test
- public void hasExpectedRules() {
- PylintRuleParser pylintRuleParser = new PylintRuleParser(PylintRuleRepository.RULES_FILE);
- assertThat(pylintRuleParser.hasRuleDefinition("C0102")).isTrue();
- assertThat(pylintRuleParser.hasRuleDefinition("C9999")).isFalse();
- }
-
- @Test
- public void logsWhenEmpty() {
- new PylintRuleParser("/org/sonar/plugins/python/pylint/empty.xml");
- assertThat(logTester.logs()).containsExactly(NO_RULE_FOUND_MESSAGE);
- }
-
- @Test
- public void logsWhenFileNotFound() {
- new PylintRuleParser("/org/sonar/plugins/python/pylint/no-file.xml");
- assertThat(logTester.logs()).containsExactly("Unable to parse the Pylint rules definition XML file", NO_RULE_FOUND_MESSAGE);
- }
-
- @Test
- public void logsWhenException() {
- new PylintRuleParser("/org/sonar/plugins/python/pylint/pylint-report.txt");
- assertThat(logTester.logs()).containsExactly("Unable to parse the Pylint rules definition XML file", NO_RULE_FOUND_MESSAGE);
- }
-
-}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRuleRepositoryTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRuleRepositoryTest.java
deleted file mode 100644
index c5f7560a34..0000000000
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRuleRepositoryTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.util.List;
-import org.junit.Test;
-import org.sonar.api.server.rule.RulesDefinition;
-import org.sonar.api.server.rule.RulesDefinitionXmlLoader;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class PylintRuleRepositoryTest {
-
- @Test
- public void createRulesTest() {
- PylintRuleRepository ruleRepository = new PylintRuleRepository(new RulesDefinitionXmlLoader());
- RulesDefinition.Context context = new RulesDefinition.Context();
- ruleRepository.define(context);
-
- RulesDefinition.Repository repository = context.repository(PylintRuleRepository.REPOSITORY_KEY);
-
- assertThat(repository).isNotNull();
- assertThat(repository.language()).isEqualTo("py");
- assertThat(repository.name()).isEqualTo("Pylint");
-
- List rules = repository.rules();
- assertThat(rules).isNotNull();
- assertThat(rules).hasSize(370);
-
- long rulesWithoutRemediationCost = rules.stream()
- .filter(rule -> rule.debtRemediationFunction() == null)
- .count();
- assertThat(rulesWithoutRemediationCost).isEqualTo(0);
- }
-
-}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
deleted file mode 100644
index 23a134fbd7..0000000000
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * SonarQube Python Plugin
- * Copyright (C) 2011-2020 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.plugins.python.pylint;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import javax.annotation.Nullable;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.mockito.Mockito;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.fs.internal.DefaultInputFile;
-import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
-import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
-import org.sonar.api.batch.rule.internal.NewActiveRule;
-import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
-import org.sonar.api.batch.sensor.internal.SensorContextTester;
-import org.sonar.api.config.internal.ConfigurationBridge;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.log.LogTester;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.plugins.python.Python;
-import org.sonar.plugins.python.TestUtils;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class PylintSensorTest {
-
- private static final String FILE1_PATH = "file1.py";
- private static final File moduleBaseDir = new File("src/test/resources/org/sonar/plugins/python/pylint").getAbsoluteFile();
- public static final String C0103_RULE_KEY = "C0103";
-
- @Rule
- public LogTester logTester = new LogTester();
- @Rule
- public TemporaryFolder tmpDir = new TemporaryFolder();
-
- private File workDir = null;
- private PylintConfiguration conf;
-
- @Before
- public void setup() throws Exception {
- conf = mock(PylintConfiguration.class);
- if (workDir == null) {
- setupWorkDir();
- }
- }
-
- @Test
- public void sensor_descriptor() {
- DefaultSensorDescriptor descriptor = new DefaultSensorDescriptor();
- List warnings = new ArrayList<>();
- new PylintSensor(conf, new ConfigurationBridge(new MapSettings()), warnings::add).describe(descriptor);
- assertThat(descriptor.name()).isEqualTo("PylintSensor");
- assertThat(descriptor.languages()).containsOnly("py");
- assertThat(descriptor.type()).isEqualTo(InputFile.Type.MAIN);
- assertThat(descriptor.ruleRepositories()).containsExactly(PylintRuleRepository.REPOSITORY_KEY);
- assertThat(warnings).isEmpty();
- }
-
- @Test
- public void shouldExecuteOnlyWhenNecessary() {
- assertThat(shouldExecute(null)).isTrue();
- assertThat(shouldExecute("result.txt")).isFalse();
- }
-
- @Test
- public void testWhenNoPylint() {
- SensorContextTester context = SensorContextTester.create(workDir);
- context.fileSystem().setWorkDir(workDir.toPath());
- when(conf.getPylintPath()).thenReturn("[---/this/should/definitely/not/exist---]");
-
- List warnings = new ArrayList<>();
- PylintSensor sensor = new PylintSensor(conf, new ConfigurationBridge(new MapSettings()), warnings::add);
- sensor.execute(context);
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Unable to use pylint for analysis. Error:");
- assertThat(warnings).isEmpty();
- }
-
- @Test
- public void testWithFakePylint() throws IOException {
- SensorContextTester context = SensorContextTester.create(workDir);
- context.fileSystem().setWorkDir(workDir.toPath());
-
- createInputFile(workDir, context, FILE1_PATH);
-
- context.setActiveRules(
- new ActiveRulesBuilder()
- .addRule(new NewActiveRule.Builder()
- .setRuleKey(RuleKey.of(PylintRuleRepository.REPOSITORY_KEY, C0103_RULE_KEY))
- .setName("Invalid name")
- .build())
- .build());
-
- Issue issue1 = new Issue(FILE1_PATH, 1, C0103_RULE_KEY, "name1", "desc1");
- Issue issue2 = new Issue(FILE1_PATH, 2, "C0111", "name2", "desc2");
- Issue issue3 = new Issue(FILE1_PATH, 3, "C9999", "name3", "desc3");
-
- MapSettings settings = new MapSettings();
- settings.setProperty(PylintImportSensor.REPORT_PATH_KEY, "report-is-set");
- List warnings = new ArrayList<>();
- PylintSensor sensor = spy(new PylintSensor(conf, new ConfigurationBridge(settings), warnings::add));
- PylintIssuesAnalyzer analyzer = mock(PylintIssuesAnalyzer.class);
- String absolutePath = new File(FILE1_PATH).getAbsolutePath().replace("\\", "/");
- when(analyzer.analyze(Mockito.eq(absolutePath), any(), any())).thenReturn(asList(issue1, issue2, issue3));
- doReturn(analyzer).when(sensor).createAnalyzer(any(), any());
-
- sensor.execute(context);
-
- // sensor was not executed as the 'sonar.python.pylint.reportPath' is set
- assertThat(context.allIssues()).hasSize(0);
- assertThat(warnings).hasSize(1);
- assertThat(warnings.get(0)).isEqualTo("Deprecation notice and future breaking changes: The import of Pylint issues will soon change. " +
- "Please follow the instructions in documentation’s section \"Analyzing Source Code\" >> \"Languages\" >> \"Python\" >> \"Pylint\".");
-
- PylintImportSensor.clearLoggedWarnings();
- settings.clear();
- sensor.execute(context);
-
- assertThat(context.allIssues()).hasSize(1);
- assertThat(context.allIssues().iterator().next().ruleKey().rule()).isEqualTo(C0103_RULE_KEY);
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Pylint rule 'C9999' is unknown in Sonar");
- assertThat(logTester.logs(LoggerLevel.WARN)).doesNotContain("Pylint rule 'C0111' is unknown in Sonar");
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Execution of Pylint is deprecated and will be removed." +
- " Instead, Pylint should be executed before sonar-scanner and its report should be imported using the 'sonar.python.pylint.reportPath' property.");
- }
-
- @Test
- public void testErrorOnFileContinueAnalysis() throws IOException {
- SensorContextTester context = SensorContextTester.create(workDir);
- context.fileSystem().setWorkDir(workDir.toPath());
-
- createInputFile(workDir, context, FILE1_PATH);
- createInputFile(workDir, context, "file2.py");
-
- List warnings = new ArrayList<>();
- PylintSensor sensor = spy(new PylintSensor(conf, new ConfigurationBridge(new MapSettings()), warnings::add));
- PylintIssuesAnalyzer analyzer = mock(PylintIssuesAnalyzer.class);
- when(analyzer.analyze(any(), any(), any())).thenThrow(RuntimeException.class);
- doReturn(analyzer).when(sensor).createAnalyzer(any(), any());
-
- sensor.execute(context);
- assertThat(logTester.logs(LoggerLevel.WARN)).contains("Cannot analyse file 'file1.py', the following exception occurred:");
- // no rule activated = no warning
- assertThat(warnings).isEmpty();
- verify(analyzer, times(2)).analyze(any(), any(), any());
- }
-
- private static void createInputFile(File baseDir, SensorContextTester context, String filePath) {
- File file = new File(baseDir, filePath);
- DefaultInputFile inputFile = TestInputFileBuilder.create("", filePath)
- .setLanguage(Python.KEY)
- .initMetadata(TestUtils.fileContent(file, StandardCharsets.UTF_8))
- .build();
- context.fileSystem().add(inputFile);
- }
-
- private boolean shouldExecute(@Nullable String pylintReportPath) {
- MapSettings settings = new MapSettings();
- if (pylintReportPath != null) {
- settings.setProperty(PylintImportSensor.REPORT_PATH_KEY, pylintReportPath);
- }
- PylintSensor sensor = new PylintSensor(conf, new ConfigurationBridge(settings), s -> {});
- return sensor.shouldExecute();
- }
-
- private void setupWorkDir() throws Exception {
- workDir = tmpDir.newFolder("python-pylint");
-
- Path file1SourcePath = new File(moduleBaseDir, "src/file1.py").toPath();
- Path file1TargetPath = new File(workDir, FILE1_PATH).toPath();
- Path file2SourcePath = new File(moduleBaseDir, "src/file2.py").toPath();
- Path file2TargetPath = new File(workDir, "file2.py").toPath();
-
- Files.copy(file1SourcePath, file1TargetPath);
- Files.copy(file2SourcePath, file2TargetPath);
- }
-
-}
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/empty.xml b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/empty.xml
deleted file mode 100644
index 0a3d245827..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/empty.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/executable b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/executable
deleted file mode 100755
index e69de29bb2..0000000000
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylintrc_sample b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylintrc_sample
deleted file mode 100644
index 0dbb2680c7..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylintrc_sample
+++ /dev/null
@@ -1,309 +0,0 @@
-# lint Python modules using external checkers.
-#
-# This is the main checker controlling the other ones and the reports
-# generation. It is itself both a raw checker and an astng checker in order
-# to:
-# * handle message activation / deactivation at the module level
-# * handle some basic but necessary stats'data (number of classes, methods...)
-#
-[MASTER]
-
-# Specify a configuration file.
-#rcfile=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Profiled execution.
-profile=no
-
-# Add to the black list. It should be a base name, not a
-# path. You may set this option multiple times.
-ignore=CVS .svn
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# Set the cache size for astng objects.
-cache-size=500
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-
-[MESSAGES CONTROL]
-
-# Enable only checker(s) with the given id(s). This option conflicts with the
-# disable-checker option
-#enable-checker=
-
-# Enable all checker(s) except those with the given id(s). This option
-# conflicts with the enable-checker option
-#disable-checker=
-
-# Enable all messages in the listed categories (IRCWEF).
-#enable-msg-cat=
-
-# Disable all messages in the listed categories (IRCWEF).
-disable-msg-cat=I
-
-# Enable the message(s) with the given id(s).
-#enable-msg=
-
-# Disable the message(s) with the given id(s).
-disable-msg=W0704 C0103
-
-
-[REPORTS]
-
-# Set the output format. Available formats are text, parseable, colorized, msvs
-# (visual studio) and html
-output-format=text
-
-# Include message's id in output
-include-ids=no
-
-# Put messages in a separate file for each module / package specified on the
-# command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
-files-output=no
-
-# Tells whether to display a full report or only the messages
-reports=yes
-
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (R0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Add a comment according to your evaluation note. This is used by the global
-# evaluation report (R0004).
-comment=no
-
-# Enable the report(s) with the given id(s).
-#enable-report=
-
-# Disable the report(s) with the given id(s).
-#disable-report=
-
-
-# try to find bugs in the code using type inference
-#
-[TYPECHECK]
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set).
-ignored-classes=SQLObject
-
-# When zope mode is activated, add a predefined set of Zope acquired attributes
-# to generated-members.
-zope=no
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed.
-generated-members=REQUEST,acl_users,aq_parent
-
-
-# checks for
-# * unused variables / imports
-# * undefined variables
-# * redefinition of variable from builtins or from an outer scope
-# * use of variable before assignment
-#
-[VARIABLES]
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# A regular expression matching names used for dummy variables (i.e. not used).
-dummy-variables-rgx=_|dummy
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-
-# checks for :
-# * doc strings
-# * modules / classes / functions / methods / arguments / variables name
-# * number of arguments, local variables, branches, returns and statements in
-# functions, methods
-# * required module attributes
-# * dangerous default values as arguments
-# * redefinition of function / method / class
-# * uses of the global statement
-#
-[BASIC]
-
-# Required attributes for module, separated by a comma
-required-attributes=
-
-# Regular expression which should only match functions or classes name which do
-# not require a docstring
-no-docstring-rgx=__.*__
-
-# Regular expression which should only match correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Regular expression which should only match correct module level names
-const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
-# Regular expression which should only match correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
-
-# Regular expression which should only match correct function names
-function-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct method names
-method-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct instance attribute names
-attr-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct argument names
-argument-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct variable names
-variable-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct list comprehension /
-# generator expression variable names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-
-# Good variable names which should always be accepted, separated by a comma
-good-names=i,j,k,ex,Run,_
-
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
-
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=map,filter,apply,input
-
-
-# checks for :
-# * methods without self as first argument
-# * overridden methods signature
-# * access only to existent members via self
-# * attributes not defined in the __init__ method
-# * supported interfaces implementation
-# * unreachable code
-#
-[CLASSES]
-
-# List of interface methods to ignore, separated by a comma. This is used for
-# instance to not check methods defines in Zope's Interface base class.
-ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
-
-
-# checks for sign of poor/misdesign:
-# * number of methods, attributes, local variables...
-# * size, complexity of functions, methods
-#
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=5
-
-# Maximum number of locals for function / method body
-max-locals=15
-
-# Maximum number of return / yield for function / method body
-max-returns=6
-
-# Maximum number of branch for function / method body
-max-branchs=12
-
-# Maximum number of statements in function / method body
-max-statements=50
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=7
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-
-# checks for
-# * external modules dependencies
-# * relative / wildcard imports
-# * cyclic imports
-# * uses of deprecated modules
-#
-[IMPORTS]
-
-# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,string,TERMIOS,Bastion,rexec
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report R0402 must not be disabled)
-import-graph=
-
-# Create a graph of external dependencies in the given file (report R0402 must
-# not be disabled)
-ext-import-graph=
-
-# Create a graph of internal dependencies in the given file (report R0402 must
-# not be disabled)
-int-import-graph=
-
-
-# checks for:
-# * warning notes in the code like FIXME, XXX
-# * PEP 263: source code with non ascii character but no encoding declaration
-#
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
-
-
-# checks for similarities and duplicated code. This computation may be
-# memory / CPU intensive, so you should disable it if you experiments some
-# problems.
-#
-[SIMILARITIES]
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-
-# checks for :
-# * unauthorized constructions
-# * strict indentation
-# * line length
-# * use of <> instead of !=
-#
-[FORMAT]
-
-# Maximum number of characters on a single line.
-max-line-length=80
-
-# Maximum number of lines in a module
-max-module-lines=1000
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string=' '
From 877c7c75032269ee74412c1ed27c689b6a02a73b Mon Sep 17 00:00:00 2001
From: Guillaume Dequenne
Date: Thu, 9 Jul 2020 14:22:18 +0200
Subject: [PATCH 3/5] SONARPY-749 Add new style importing of Pylint reports
(#808)
---
.../python/it/plugin/PylintReportTest.java | 22 +-
.../com/sonar/python/it/plugin/Tests.java | 1 +
.../plugins/python/ExternalIssuesSensor.java | 55 +-
.../sonar/plugins/python/PythonPlugin.java | 19 +-
...eportReader.java => TextReportReader.java} | 87 +-
.../plugins/python/bandit/BanditSensor.java | 14 +-
.../plugins/python/flake8/Flake8Sensor.java | 49 +-
.../python/pylint/PylintRulesDefinition.java | 36 +
.../plugins/python/pylint/PylintSensor.java | 61 +
.../sonar/plugins/python/pylint/rules.json | 1852 +++++++++++++++++
.../plugins/python/PythonPluginTest.java | 8 +-
.../pylint/PylintRulesDefinitionTest.java | 52 +
.../python/pylint/PylintSensorTest.java | 240 +++
.../org/sonar/plugins/python/pylint/file1.py | 30 +
.../pylint/pylint-report-unknown-rules.txt | 7 -
.../plugins/python/pylint/pylint-report.txt | 4 -
.../plugins/python/pylint/pylint_brackets.txt | 10 +
.../pylint/pylint_names_in_brackets.txt | 1 +
.../pylint/pylint_report_default_format.txt | 14 +
.../python/pylint/pylint_report_no_column.txt | 4 +
.../pylint/pylint_report_unknown_files.txt | 13 +
.../python/pylint/sample_pylint_output.txt | 21 -
.../sample_pylint_output_new_format.txt | 2 -
.../pylint/sample_pylint_output_newids.txt | 10 -
.../pylint/sample_pylint_output_oldids.txt | 10 -
.../sample_pylint_output_with_win_paths.txt | 1 -
.../sonar/plugins/python/pylint/src/file1.py | 1 -
.../sonar/plugins/python/pylint/src/file2.py | 1 -
28 files changed, 2461 insertions(+), 164 deletions(-)
rename sonar-python-plugin/src/main/java/org/sonar/plugins/python/{flake8/Flake8ReportReader.java => TextReportReader.java} (52%)
create mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRulesDefinition.java
create mode 100644 sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
create mode 100644 sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules.json
create mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRulesDefinitionTest.java
create mode 100644 sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
create mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/file1.py
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint-report-unknown-rules.txt
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint-report.txt
create mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_brackets.txt
create mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_names_in_brackets.txt
create mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_default_format.txt
create mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_no_column.txt
create mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_unknown_files.txt
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output.txt
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_new_format.txt
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_newids.txt
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_oldids.txt
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_with_win_paths.txt
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/src/file1.py
delete mode 100644 sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/src/file2.py
diff --git a/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/PylintReportTest.java b/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/PylintReportTest.java
index 8a98ac2d04..153294b9d1 100644
--- a/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/PylintReportTest.java
+++ b/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/PylintReportTest.java
@@ -49,38 +49,42 @@ public void import_report() {
@Test
public void missing_report() {
analyseProjectWithReport("missing");
- assertThat(issues()).hasSize(0);
+ assertThat(issues()).isEmpty();
}
@Test
public void invalid_report() {
BuildResult result = analyseProjectWithReport("invalid.txt");
assertThat(result.getLogs()).contains("Cannot parse the line: trash");
- assertThat(issues()).hasSize(0);
+ assertThat(issues()).isEmpty();
}
@Test
public void unknown_rule() {
BuildResult result = analyseProjectWithReport("rule-unknown.txt");
- assertThat(result.getLogs()).doesNotContain("Pylint rule 'C0102' is unknown");
- assertThat(result.getLogs()).containsOnlyOnce("Pylint rule 'C8888' is unknown");
- assertThat(result.getLogs()).containsOnlyOnce("Pylint rule 'C9999' is unknown");
- assertThat(issues()).hasSize(0);
+ assertThat(issues()).hasSize(4);
+ }
+
+ @Test
+ public void multiple_reports() {
+ analyseProjectWithReport("pylint-report.txt, rule-unknown.txt");
+ assertThat(issues()).hasSize(8);
}
private static List issues() {
return newWsClient().issues().search(new SearchRequest().setProjects(singletonList(PROJECT))).getIssuesList();
}
- private static BuildResult analyseProjectWithReport(String reportPath) {
+ private static BuildResult analyseProjectWithReport(String reportPaths) {
ORCHESTRATOR.resetData();
ORCHESTRATOR.getServer().provisionProject(PROJECT, PROJECT);
- ORCHESTRATOR.getServer().associateProjectToQualityProfile(PROJECT, "py", "pylint-rules");
+ ORCHESTRATOR.getServer().associateProjectToQualityProfile(PROJECT, "py", "no_rule");
+
return ORCHESTRATOR.executeBuild(
SonarScanner.create()
.setDebugLogs(true)
.setProjectDir(new File("projects/pylint_project"))
- .setProperty("sonar.python.pylint.reportPath", reportPath));
+ .setProperty("sonar.python.pylint.reportPaths", reportPaths));
}
}
diff --git a/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/Tests.java b/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/Tests.java
index 62278cf0fa..0da2259c53 100644
--- a/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/Tests.java
+++ b/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/Tests.java
@@ -47,6 +47,7 @@
@RunWith(Suite.class)
@Suite.SuiteClasses({
BanditReportTest.class,
+ PylintReportTest.class,
MetricsTest.class,
CPDTest.class,
CoverageTest.class,
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java
index 84e25d7d9f..42f384262c 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java
@@ -21,19 +21,27 @@
import java.io.File;
+import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import org.sonar.api.utils.log.Logger;
import java.util.stream.Collectors;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.Sensor;
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.SensorDescriptor;
+import org.sonar.api.batch.sensor.issue.NewExternalIssue;
+import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.utils.log.Logger;
import org.sonarsource.analyzer.commons.ExternalReportProvider;
+import org.sonarsource.analyzer.commons.internal.json.simple.parser.ParseException;
public abstract class ExternalIssuesSensor implements Sensor {
private static final int MAX_LOGGED_FILE_NAMES = 20;
+ private static final Long DEFAULT_CONSTANT_DEBT_MINUTES = 5L;
@Override
public void describe(SensorDescriptor descriptor) {
@@ -47,10 +55,18 @@ public void describe(SensorDescriptor descriptor) {
public void execute(SensorContext context) {
Set unresolvedInputFiles = new HashSet<>();
List reportFiles = ExternalReportProvider.getReportFiles(context, reportPathKey());
- reportFiles.forEach(report -> importReport(report, context, unresolvedInputFiles));
+ reportFiles.forEach(report -> importExternalReport(report, context, unresolvedInputFiles));
logUnresolvedInputFiles(unresolvedInputFiles);
}
+ private void importExternalReport(File reportPath, SensorContext context, Set unresolvedInputFiles) {
+ try {
+ importReport(reportPath, context, unresolvedInputFiles);
+ } catch (IOException | ParseException | RuntimeException e) {
+ logFileCantBeRead(e, reportPath);
+ }
+ }
+
private void logUnresolvedInputFiles(Set unresolvedInputFiles) {
if (unresolvedInputFiles.isEmpty()) {
return;
@@ -62,7 +78,40 @@ private void logUnresolvedInputFiles(Set unresolvedInputFiles) {
logger().warn("Failed to resolve {} file path(s) in " + linterName() + " report. No issues imported related to file(s): {}", unresolvedInputFiles.size(), fileList);
}
- protected abstract void importReport(File reportPath, SensorContext context, Set unresolvedInputFiles);
+ private void logFileCantBeRead(Exception e, File reportPath) {
+ logger().error("No issues information will be saved as the report file '{}' can't be read. {}: {}"
+ , reportPath, e.getClass().getSimpleName(), e.getMessage());
+ }
+
+ protected void saveIssue(SensorContext context, TextReportReader.Issue issue, Set unresolvedInputFiles, String linterKey) {
+ InputFile inputFile = context.fileSystem().inputFile(context.fileSystem().predicates().hasPath(issue.filePath));
+ if (inputFile == null) {
+ unresolvedInputFiles.add(issue.filePath);
+ return;
+ }
+
+ NewExternalIssue newExternalIssue = context.newExternalIssue();
+ newExternalIssue
+ .type(RuleType.CODE_SMELL)
+ .severity(Severity.MAJOR)
+ .remediationEffortMinutes(DEFAULT_CONSTANT_DEBT_MINUTES);
+
+ NewIssueLocation primaryLocation = newExternalIssue.newLocation()
+ .message(issue.message)
+ .on(inputFile);
+ if (issue.columnNumber != null && issue.columnNumber < inputFile.selectLine(issue.lineNumber).end().lineOffset()) {
+ primaryLocation.at(inputFile.newRange(issue.lineNumber, issue.columnNumber, issue.lineNumber, issue.columnNumber + 1));
+ } else {
+ // Pylint formatted issues might not provide column information
+ primaryLocation.at(inputFile.selectLine(issue.lineNumber));
+ }
+
+ newExternalIssue.at(primaryLocation);
+ newExternalIssue.engineId(linterKey).ruleId(issue.ruleKey);
+ newExternalIssue.save();
+ }
+
+ protected abstract void importReport(File reportPath, SensorContext context, Set unresolvedInputFiles) throws IOException, ParseException;
protected abstract String linterName();
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java
index c2ccfd1613..311d0eb471 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonPlugin.java
@@ -31,6 +31,8 @@
import org.sonar.plugins.python.coverage.PythonCoverageSensor;
import org.sonar.plugins.python.flake8.Flake8RulesDefinition;
import org.sonar.plugins.python.flake8.Flake8Sensor;
+import org.sonar.plugins.python.pylint.PylintRulesDefinition;
+import org.sonar.plugins.python.pylint.PylintSensor;
import org.sonar.plugins.python.warnings.DefaultAnalysisWarningsWrapper;
import org.sonar.plugins.python.xunit.PythonXUnitSensor;
@@ -75,6 +77,7 @@ public void define(Context context) {
context.addExtension(DefaultAnalysisWarningsWrapper.class);
addCoberturaExtensions(context);
addXUnitExtensions(context);
+ addPylintExtensions(context);
addBanditExtensions(context);
addFlake8Extensions(context);
}
@@ -148,9 +151,21 @@ private static void addBanditExtensions(Context context) {
}
}
+ private static void addPylintExtensions(Context context) {
+ context.addExtensions(PylintSensor.class,
+ PropertyDefinition.builder(PylintSensor.REPORT_PATH_KEY)
+ .name("Pylint Report Files")
+ .description("Paths (absolute or relative) to report files with Pylint issues.")
+ .category(EXTERNAL_ANALYZERS_CATEGORY)
+ .subCategory(PYTHON_CATEGORY)
+ .onQualifiers(Qualifiers.PROJECT)
+ .multiValues(true)
+ .build(),
+ PylintRulesDefinition.class);
+ }
+
private static void addFlake8Extensions(Context context) {
- context.addExtension(Flake8Sensor.class);
- context.addExtensions(
+ context.addExtensions(Flake8Sensor.class,
PropertyDefinition.builder(Flake8Sensor.REPORT_PATH_KEY)
.name("Flake8 Report Files")
.description("Paths (absolute or relative) to report files with Flake8 issues.")
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8ReportReader.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/TextReportReader.java
similarity index 52%
rename from sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8ReportReader.java
rename to sonar-python-plugin/src/main/java/org/sonar/plugins/python/TextReportReader.java
index 70fc64d80b..3df25d3051 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8ReportReader.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/TextReportReader.java
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-package org.sonar.plugins.python.flake8;
+package org.sonar.plugins.python;
import java.io.File;
import java.io.IOException;
@@ -31,11 +31,22 @@
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-public class Flake8ReportReader {
+/**
+ * Common implementation to parse Flake8 and Pylint reports
+ */
+public class TextReportReader {
+
+ private static final Pattern DEFAULT_PATTERN = Pattern.compile("(.+):(\\d+):(\\d+): (\\S+[^:]):? (.*)");
+ private static final Pattern LEGACY_PATTERN = Pattern.compile("(.+):(\\d+): \\[(.*)\\] (.*)");
+ private static final Logger LOG = Loggers.get(TextReportReader.class);
+ public static final int COLUMN_ZERO_BASED = 0;
+ public static final int COLUMN_ONE_BASED = 1;
+
+ private final int reportOffset;
- private static final Logger LOG = Loggers.get(Flake8ReportReader.class);
- private static final Pattern DEFAULT_PATTERN = Pattern.compile("(.+):(\\d+):(\\d+): (\\S+) (.*)");
- private static final Pattern PYLINT_PATTERN = Pattern.compile("(.+):(\\d+): \\[(.*)\\] (.*)");
+ public TextReportReader(int columnStartIndex) {
+ this.reportOffset = columnStartIndex;
+ }
public List parse(File report, FileSystem fileSystem) throws IOException {
List issues = new ArrayList<>();
@@ -50,51 +61,55 @@ public List parse(File report, FileSystem fileSystem) throws IOException
return issues;
}
- private static Issue parseLine(String line) {
-
+ private Issue parseLine(String line) {
if (line.length() > 0) {
- if (!startsWithWhitespace(line)) {
- Matcher m = DEFAULT_PATTERN.matcher(line);
- if (m.matches()) {
- String filePath = m.group(1);
- int lineNumber = Integer.parseInt(m.group(2));
- int columnNumber = Integer.parseInt(m.group(3));
- String ruleKey = m.group(4);
- String message = m.group(5);
- return new Issue(filePath, ruleKey, message, lineNumber, columnNumber);
- }
- m = PYLINT_PATTERN.matcher(line);
- if (m.matches()) {
- String filePath = m.group(1);
- int lineNumber = Integer.parseInt(m.group(2));
- String ruleKey = m.group(3);
- String message = m.group(4);
- return new Issue(filePath, ruleKey, message, lineNumber, null);
- }
- LOG.debug("Cannot parse the line: {}", line);
- } else {
- LOG.debug("Classifying as detail and ignoring line '{}'", line);
+ Matcher m = TextReportReader.DEFAULT_PATTERN.matcher(line);
+ if (m.matches()) {
+ return extractDefaultStyleIssue(m);
+ }
+ m = TextReportReader.LEGACY_PATTERN.matcher(line);
+ if (m.matches()) {
+ return extractLegacyStyleIssue(m);
}
+ LOG.debug("Cannot parse the line: {}", line);
}
return null;
}
- private static boolean startsWithWhitespace(String line) {
- char first = line.charAt(0);
- return first == ' ' || first == '\t' || first == '\n';
+ private Issue extractDefaultStyleIssue(Matcher m) {
+ String filePath = m.group(1);
+ int lineNumber = Integer.parseInt(m.group(2));
+ int columnNumber = Integer.parseInt(m.group(3));
+ // Flake8 column numbering starts at 1
+ columnNumber -= this.reportOffset;
+ String ruleKey = m.group(4);
+ String message = m.group(5);
+ return new Issue(filePath, ruleKey, message, lineNumber, columnNumber);
+ }
+
+ private static Issue extractLegacyStyleIssue(Matcher m) {
+ String filePath = m.group(1);
+ int lineNumber = Integer.parseInt(m.group(2));
+ String ruleKey = m.group(3);
+ int keyLastIndex = ruleKey.indexOf("(");
+ if (keyLastIndex > 0) {
+ ruleKey = ruleKey.substring(0, keyLastIndex);
+ }
+ String message = m.group(4);
+ return new Issue(filePath, ruleKey, message, lineNumber, null);
}
public static class Issue {
- String filePath;
+ public final String filePath;
- String ruleKey;
+ public final String ruleKey;
- String message;
+ public final String message;
- Integer lineNumber;
+ public final Integer lineNumber;
- Integer columnNumber;
+ public final Integer columnNumber;
public Issue(String filePath, String ruleKey, String message, Integer lineNumber, @Nullable Integer columnNumber) {
this.filePath = filePath;
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/bandit/BanditSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/bandit/BanditSensor.java
index 352ebb5576..6c3cf60806 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/bandit/BanditSensor.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/bandit/BanditSensor.java
@@ -51,15 +51,11 @@ public class BanditSensor extends ExternalIssuesSensor {
private static final Long DEFAULT_CONSTANT_DEBT_MINUTES = 5L;
@Override
- protected void importReport(File reportPath, SensorContext context, Set unresolvedInputFiles) {
- try (InputStream in = new FileInputStream(reportPath)) {
- LOG.info("Importing {}", reportPath);
- boolean engineIdIsSupported = context.getSonarQubeVersion().isGreaterThanOrEqual(Version.create(7, 4));
- BanditJsonReportReader.read(in, issue -> saveIssue(context, issue, unresolvedInputFiles, engineIdIsSupported));
- } catch (IOException | ParseException | RuntimeException e) {
- LOG.error("No issues information will be saved as the report file '{}' can't be read. " +
- e.getClass().getSimpleName() + ": " + e.getMessage(), reportPath, e);
- }
+ protected void importReport(File reportPath, SensorContext context, Set unresolvedInputFiles) throws IOException, ParseException {
+ InputStream in = new FileInputStream(reportPath);
+ LOG.info("Importing {}", reportPath);
+ boolean engineIdIsSupported = context.getSonarQubeVersion().isGreaterThanOrEqual(Version.create(7, 4));
+ BanditJsonReportReader.read(in, issue -> saveIssue(context, issue, unresolvedInputFiles, engineIdIsSupported));
}
private static void saveIssue(SensorContext context, Issue issue, Set unresolvedInputFiles, boolean engineIdIsSupported) {
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8Sensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8Sensor.java
index d87f5aa541..365b6af6b6 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8Sensor.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8Sensor.java
@@ -23,15 +23,12 @@
import java.io.IOException;
import java.util.List;
import java.util.Set;
-import org.sonar.api.batch.fs.InputFile;
-import org.sonar.api.batch.rule.Severity;
import org.sonar.api.batch.sensor.SensorContext;
-import org.sonar.api.batch.sensor.issue.NewExternalIssue;
-import org.sonar.api.batch.sensor.issue.NewIssueLocation;
-import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.plugins.python.ExternalIssuesSensor;
+import org.sonar.plugins.python.TextReportReader;
+import org.sonar.plugins.python.TextReportReader.Issue;
public class Flake8Sensor extends ExternalIssuesSensor {
@@ -41,46 +38,10 @@ public class Flake8Sensor extends ExternalIssuesSensor {
public static final String LINTER_KEY = "flake8";
public static final String REPORT_PATH_KEY = "sonar.python.flake8.reportPaths";
- private static final Long DEFAULT_CONSTANT_DEBT_MINUTES = 5L;
-
@Override
- protected void importReport(File reportPath, SensorContext context, Set unresolvedInputFiles) {
- try {
- List issues = new Flake8ReportReader().parse(reportPath, context.fileSystem());
- issues.forEach(i -> saveIssue(context, i, unresolvedInputFiles));
- } catch (IOException e) {
- LOG.error("No issues information will be saved as the report file '{}' can't be read. " +
- e.getClass().getSimpleName() + ": " + e.getMessage(), reportPath, e);
- }
- }
-
- private static void saveIssue(SensorContext context, Flake8ReportReader.Issue issue, Set unresolvedInputFiles) {
- InputFile inputFile = context.fileSystem().inputFile(context.fileSystem().predicates().hasPath(issue.filePath));
- if (inputFile == null) {
- unresolvedInputFiles.add(issue.filePath);
- return;
- }
-
- NewExternalIssue newExternalIssue = context.newExternalIssue();
- newExternalIssue
- .type(RuleType.CODE_SMELL)
- .severity(Severity.MAJOR)
- .remediationEffortMinutes(DEFAULT_CONSTANT_DEBT_MINUTES);
-
- NewIssueLocation primaryLocation = newExternalIssue.newLocation()
- .message(issue.message)
- .on(inputFile);
- if (issue.columnNumber != null && issue.columnNumber < inputFile.selectLine(issue.lineNumber).end().lineOffset() + 1) {
- inputFile.selectLine(issue.lineNumber).end().lineOffset();
- primaryLocation.at(inputFile.newRange(issue.lineNumber, issue.columnNumber - 1, issue.lineNumber, issue.columnNumber));
- } else {
- // Pylint formatted issues don't provide column information
- primaryLocation.at(inputFile.selectLine(issue.lineNumber));
- }
-
- newExternalIssue.at(primaryLocation);
- newExternalIssue.engineId(LINTER_KEY).ruleId(issue.ruleKey);
- newExternalIssue.save();
+ protected void importReport(File reportPath, SensorContext context, Set unresolvedInputFiles) throws IOException {
+ List issues = new TextReportReader(TextReportReader.COLUMN_ONE_BASED).parse(reportPath, context.fileSystem());
+ issues.forEach(i -> saveIssue(context, i, unresolvedInputFiles, LINTER_KEY));
}
@Override
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRulesDefinition.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRulesDefinition.java
new file mode 100644
index 0000000000..83117d6e04
--- /dev/null
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintRulesDefinition.java
@@ -0,0 +1,36 @@
+/*
+ * SonarQube Python Plugin
+ * Copyright (C) 2011-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.python.pylint;
+
+import org.sonar.api.server.rule.RulesDefinition;
+import org.sonar.plugins.python.Python;
+import org.sonarsource.analyzer.commons.ExternalRuleLoader;
+
+public class PylintRulesDefinition implements RulesDefinition {
+
+ private static final String RULES_JSON = "org/sonar/plugins/python/pylint/rules.json";
+ private static final ExternalRuleLoader RULE_LOADER = new ExternalRuleLoader(PylintSensor.LINTER_KEY, PylintSensor.LINTER_NAME, RULES_JSON, Python.KEY);
+
+
+ @Override
+ public void define(RulesDefinition.Context context) {
+ RULE_LOADER.createExternalRuleRepository(context);
+ }
+}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
new file mode 100644
index 0000000000..1e808985eb
--- /dev/null
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
@@ -0,0 +1,61 @@
+/*
+ * SonarQube Python Plugin
+ * Copyright (C) 2011-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.python.pylint;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Set;
+import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.plugins.python.ExternalIssuesSensor;
+import org.sonar.plugins.python.TextReportReader;
+import org.sonar.plugins.python.TextReportReader.Issue;
+
+public class PylintSensor extends ExternalIssuesSensor {
+
+ private static final Logger LOG = Loggers.get(PylintSensor.class);
+
+ public static final String LINTER_NAME = "Pylint";
+ public static final String LINTER_KEY = "pylint";
+ public static final String REPORT_PATH_KEY = "sonar.python.pylint.reportPaths";
+
+ @Override
+ protected void importReport(File reportPath, SensorContext context, Set unresolvedInputFiles) throws IOException {
+ List issues = new TextReportReader(TextReportReader.COLUMN_ZERO_BASED).parse(reportPath, context.fileSystem());
+ issues.forEach(i -> saveIssue(context, i, unresolvedInputFiles, LINTER_KEY));
+ }
+
+ @Override
+ protected String reportPathKey() {
+ return REPORT_PATH_KEY;
+ }
+
+ @Override
+ protected String linterName() {
+ return LINTER_NAME;
+ }
+
+ @Override
+ protected Logger logger() {
+ return LOG;
+ }
+}
diff --git a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules.json b/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules.json
new file mode 100644
index 0000000000..89ae29a3aa
--- /dev/null
+++ b/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules.json
@@ -0,0 +1,1852 @@
+[
+ {
+ "key": "C0102",
+ "name": "Black listed name",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0103",
+ "name": "Invalid name",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0111",
+ "name": "Missing docstring",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0112",
+ "name": "Empty docstring",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0113",
+ "name": "Useless negation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0121",
+ "name": "Singleton comparison",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0122",
+ "name": "Misplaced comparison constant",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0123",
+ "name": "Using type() instead of isinstance() for a typecheck.",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0200",
+ "name": "Consider using enumerate instead of iterating with range and len",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0201",
+ "name": "Consider iterating the dictionary directly instead of calling .keys()",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0202",
+ "name": "Class method should have \"cls\" as first argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0203",
+ "name": "Metaclass method should have \"mcs\" as first argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0204",
+ "name": "Metaclass class method first argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0205",
+ "name": "Class __slots__ should be a non-string iterable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0301",
+ "name": "Line too long",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0302",
+ "name": "Too many lines in module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0303",
+ "name": "Trailing whitespace",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0304",
+ "name": "Final newline missing",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0305",
+ "name": "Trailing newlines",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0321",
+ "name": "More than one statement on a single line",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0322",
+ "name": "Operator not preceded by a space",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0323",
+ "name": "Operator not followed by a space",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0324",
+ "name": "Comma not followed by a space",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0325",
+ "name": "Unnecessary parentheses",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0326",
+ "name": "Wrong number of spaces around an operator, bracket, or comma, or before a block opener",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0327",
+ "name": "Mixed line endings LF and CRLF",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0328",
+ "name": "Unexpected line ending format",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0330",
+ "name": "Bad continuation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0401",
+ "name": "Wrong spelling of a word in a comment",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0402",
+ "name": "Wrong spelling of a word in a docstring",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0403",
+ "name": "Invalid characters in a docstring",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0410",
+ "name": "Multiple imports on one line",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0411",
+ "name": "Wrong import order",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0412",
+ "name": "Ungrouped imports",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0413",
+ "name": "Wrong import position",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C1001",
+ "name": "Old-style class defined.",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C0414",
+ "name": "Import alias does not rename original package",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "C1801",
+ "name": "Do not use `len(SEQUENCE)` to determine if a sequence is empty",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0001",
+ "name": "Syntax error",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0011",
+ "name": "Unrecognized file option",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0012",
+ "name": "Bad option value",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0100",
+ "name": "__init__ method is a generator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0101",
+ "name": "Explicit return in __init__",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0102",
+ "name": "Redefined function/class/method",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0103",
+ "name": "Usage of 'break' or 'continue' outside of a loop",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0104",
+ "name": "Return outside function",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0105",
+ "name": "Yield outside function",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0106",
+ "name": "Return with argument inside generator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0107",
+ "name": "Use of a non-existent operator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0108",
+ "name": "Duplicate argument name in function definition",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0109",
+ "name": "Missing argument to reversed()",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0110",
+ "name": "Abstract class instantiated",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0111",
+ "name": "The first reversed() argument is not a sequence",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0112",
+ "name": "More than one starred expression in assignment",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0113",
+ "name": "Starred assignment target must be in a list or tuple",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0114",
+ "name": "Can use starred expression only in assignment target",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0115",
+ "name": "Name is nonlocal and global",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0116",
+ "name": "'continue' not supported inside 'finally' clause",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0117",
+ "name": "Nonlocal name found without binding",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0119",
+ "name": "Format function is not called on str",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0202",
+ "name": "Method hidden by attribute of super class",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0203",
+ "name": "Access to member before its definition",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0211",
+ "name": "Method has no argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0213",
+ "name": "Method should have \"self\" as first argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0221",
+ "name": "Implemented interface must be a class",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0222",
+ "name": "Missing method from interface",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0235",
+ "name": "__exit__ must accept 3 arguments: type, value, traceback",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0236",
+ "name": "Invalid object in __slots__, must contain only non empty strings",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0237",
+ "name": "Assigning to attribute not defined in class slots",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0238",
+ "name": "Invalid __slots__ object",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0239",
+ "name": "Inheriting from non-class",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0240",
+ "name": "Inconsistent method resolution order",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0241",
+ "name": "Duplicate bases",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0301",
+ "name": "__iter__ returns non-iterator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0302",
+ "name": "Unexpected special method signature",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0303",
+ "name": "__len__ does not return non-negative integer",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0401",
+ "name": "Import error",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0402",
+ "name": "Attempted relative import beyond top-level package",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0501",
+ "name": "Non-ASCII characters found but no encoding specified (PEP 263)",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0502",
+ "name": "Wrong encoding specified",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0503",
+ "name": "Unknown encoding specified",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0601",
+ "name": "Using variable before assignment",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0602",
+ "name": "Undefined variable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0603",
+ "name": "Undefined variable name in __all__",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0604",
+ "name": "Invalid object in __all__, must contain only strings",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0611",
+ "name": "Undefined name in module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0632",
+ "name": "Unbalanced tuple unpacking",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0633",
+ "name": "Attempting to unpack a non-sequence",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0701",
+ "name": "Bad except clauses order",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0702",
+ "name": "Raising only allowed for classes, instances or strings",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0703",
+ "name": "Exception context set to something which is not an exception, nor None",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0704",
+ "name": "The raise statement is not inside an except clause",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0710",
+ "name": "Raising a new style class which doesn't inherit from BaseException",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0711",
+ "name": "NotImplemented raised - should raise NotImplementedError",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E0712",
+ "name": "Catching an exception which doesn't inherit from Exception",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1001",
+ "name": "Use of __slots__ on an old style class",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1002",
+ "name": "Use of super on an old style class",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1003",
+ "name": "Bad first argument given to super",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1004",
+ "name": "Missing argument to super()",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1101",
+ "name": "Access of nonexistent member",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1102",
+ "name": "Calling of not callable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1103",
+ "name": "Accessing nonexistent member (type information incomplete)",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1111",
+ "name": "Assigning result of a function call, where the function has no return",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1120",
+ "name": "Too few arguments",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1121",
+ "name": "Too many positional arguments for function call",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1122",
+ "name": "Duplicate keyword argument in function call",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1123",
+ "name": "Passing unexpected keyword argument in function call",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1124",
+ "name": "Multiple values passed for parameter in function call",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1125",
+ "name": "Missing mandatory keyword argument in call",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1126",
+ "name": "Sequence index is not an int, slice, or instance with __index__",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1127",
+ "name": "Slice index is not an int, None, or instance with __index__",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1128",
+ "name": "Assigning result of a function call, where the function returns None",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1129",
+ "name": "Context manager doesn't implement __enter__ and __exit__",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1130",
+ "name": "Invalid unary operand type",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1131",
+ "name": "Unsupported binary operation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1132",
+ "name": "Multiple values for keyword argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1133",
+ "name": "Non-iterable value used in an iterating context",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1134",
+ "name": "Non-mapping value used in a mapping context",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1135",
+ "name": "Unsupported membership test",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1136",
+ "name": "Subscripted value doesn't support subscription",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1137",
+ "name": "Object does not support item assignment",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1138",
+ "name": "Object does not support item deletion",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1139",
+ "name": "Invalid metaclass used",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1140",
+ "name": "Dict key is unhashable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1200",
+ "name": "Unsupported logging format character",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1201",
+ "name": "Logging format string ends in middle of conversion specifier",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1205",
+ "name": "Too many arguments for logging format string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1206",
+ "name": "Not enough arguments for logging format string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1300",
+ "name": "Unsupported format character",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1301",
+ "name": "Format string ends in middle of conversion specifier",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1302",
+ "name": "Mixing named and unnamed conversion specifiers in format string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1303",
+ "name": "Expected mapping for format string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1304",
+ "name": "Missing key in format string dictionary",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1305",
+ "name": "Too many arguments for format string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1306",
+ "name": "Not enough arguments for format string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1307",
+ "name": "Argument does not match format type",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1310",
+ "name": "Suspicious argument in lstrip/rstrip",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1507",
+ "name": "Env manipulation functions does not support type argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1601",
+ "name": "print statement used",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1602",
+ "name": "Parameter unpacking specified",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1603",
+ "name": "Implicit unpacking of exceptions is not supported in Python 3",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1604",
+ "name": "Use raise ErrorClass(args) instead of raise ErrorClass, args.",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1605",
+ "name": "Use of the `` operator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1606",
+ "name": "Use of long suffix",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1607",
+ "name": "Use of the <> operator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1608",
+ "name": "Use of old octal literal",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1609",
+ "name": "Import * only allowed at module level",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1610",
+ "name": "Non-ascii bytes literals not supported in 3.x",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1700",
+ "name": "Yield inside async function",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "E1701",
+ "name": "Async context manager doesn't implement __aenter__ and __aexit__",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0001",
+ "name": "Analysis failed",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0002",
+ "name": "Internal Pylint error",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0003",
+ "name": "Ignored builtin module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0004",
+ "name": "Unexpected inferred value",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0010",
+ "name": "Error while code parsing",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0202",
+ "name": "Unable to check methods signature",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0220",
+ "name": "Failed to resolve interfaces",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0321",
+ "name": "Format detection error",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "F0401",
+ "name": "Unable to import module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0001",
+ "name": "Unable to run raw checkers on built-in module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0010",
+ "name": "Unable to consider inline option",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0011",
+ "name": "Locally disabling message",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0012",
+ "name": "Locally enabling message",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0013",
+ "name": "Ignoring entire file",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0020",
+ "name": "Suppressed message",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0021",
+ "name": "Useless suppression of message",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0022",
+ "name": "Deprecated pragma",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I0023",
+ "name": "Use symbolic message",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "I1101",
+ "name": "Non-existent member of C extension",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0123",
+ "name": "Comparison to literal",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0124",
+ "name": "Redundant comparison",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0201",
+ "name": "Method could be a function",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0202",
+ "name": "Consider using a decorator instead of calling classmethod",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0203",
+ "name": "Consider using a decorator instead of calling staticmethod",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0205",
+ "name": "Class inherits from object, can be safely removed from bases in python3",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0401",
+ "name": "Cyclic import",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0801",
+ "name": "Similar lines",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0901",
+ "name": "Too many ancestors",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0902",
+ "name": "Too many instance attributes",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0903",
+ "name": "Too few public methods",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0904",
+ "name": "Too many public methods",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0911",
+ "name": "Too many return statements",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0912",
+ "name": "Too many branches",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0913",
+ "name": "Too many arguments",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0914",
+ "name": "Too many local variables",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0915",
+ "name": "Too many statements",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0916",
+ "name": "Too many boolean expressions in if statement",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0921",
+ "name": "Abstract class not referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0922",
+ "name": "Abstract class used too few times",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R0923",
+ "name": "Interface not implemented",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1701",
+ "name": "Consider merging isinstance calls",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1702",
+ "name": "Too many nested blocks",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1703",
+ "name": "Simplifiable if statement",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1704",
+ "name": "Redefining argument with local name",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1705",
+ "name": "Unnecessary \"else\" after \"return\"",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1706",
+ "name": "Consider using ternary",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1707",
+ "name": "Disallow trailing comma tuple",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1708",
+ "name": "Do not raise StopIteration in generator, use return statement instead",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1709",
+ "name": "Boolean expression may be simplified",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1710",
+ "name": "Either all return statements in a function should return an expression, or none of them should.",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1711",
+ "name": "Useless return at end of function or method",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1712",
+ "name": "Consider using tuple unpacking for swapping variables",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1713",
+ "name": "Consider using str.join(sequence) for concatenating strings from an iterable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1714",
+ "name": "Consider using \"in\"",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1715",
+ "name": "Consider using dict.get for getting values from a dict if a key is present or a default if not",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1716",
+ "name": "Simplify chained comparison between the operands",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1717",
+ "name": "Consider using a dictionary comprehension",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1718",
+ "name": "Consider using a set comprehension",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1719",
+ "name": "Simplifiable if expression",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "R1720",
+ "name": "Unnecessary \"else\" after \"raise\"",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0101",
+ "name": "Unreachable code",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0102",
+ "name": "Dangerous default value as argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0104",
+ "name": "Statement seems to have no effect",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0105",
+ "name": "String statement has no effect",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0106",
+ "name": "Expression is assigned to nothing",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0107",
+ "name": "Unnecessary pass statement",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0108",
+ "name": "Lambda may not be necessary",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0109",
+ "name": "Duplicate key in dictionary",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0110",
+ "name": "map/filter on lambda could be replaced by comprehension",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0111",
+ "name": "Assignments should not be made to new Python keywords",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0120",
+ "name": "Else clause on loop without a break statement",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0121",
+ "name": "Use raise ErrorClass(args) instead of raise ErrorClass, args.",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0122",
+ "name": "Use of exec",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0123",
+ "name": "Use of eval",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0124",
+ "name": "Following \"as\" with another context manager looks like a tuple.",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0125",
+ "name": "Using a conditional statement with a constant value",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0141",
+ "name": "Used black listed builtin function",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0142",
+ "name": "Used * or ** magic",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0143",
+ "name": "Comparing against a callable, did you omit the parenthesis?",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0150",
+ "name": "Statement in finally block may swallow exception",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0199",
+ "name": "Assert called on a 2-uple",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0201",
+ "name": "Attribute defined outside __init__",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0211",
+ "name": "Static method with \"self\" or \"cls\" as first argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0212",
+ "name": "Access to a protected member of a client class",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0221",
+ "name": "Parameter number discrepancy",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0222",
+ "name": "Method signature discrepancy",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0223",
+ "name": "Abstract method is not overridden",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0231",
+ "name": "__init__ method from base class is not called",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0232",
+ "name": "Class has no __init__ method",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0233",
+ "name": "__init__ method from a non direct base class is called",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0234",
+ "name": "__iter__ returns non-iterator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0235",
+ "name": "Useless super delegation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0301",
+ "name": "Unnecessary semicolon",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0311",
+ "name": "Bad indentation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0312",
+ "name": "Mixed tabs/spaces indentation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0331",
+ "name": "Use of the <> operator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0332",
+ "name": "Use of \"l\" as long integer identifier",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0333",
+ "name": "Use of the `` operator",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0401",
+ "name": "Wildcard import",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0402",
+ "name": "Uses of a deprecated module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0403",
+ "name": "Relative import",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0404",
+ "name": "Reimport",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0406",
+ "name": "Module imports itself",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0410",
+ "name": "__future__ import is not the first non docstring statement",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0511",
+ "name": "Task marker found",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0512",
+ "name": "Source line cannot be decoded using the specified source file encoding",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0601",
+ "name": "Global variable undefined at the module level",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0602",
+ "name": "Unassigned global variable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0603",
+ "name": "Using the global statement",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0604",
+ "name": "Using the global statement at the module level",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0611",
+ "name": "Unused import",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0612",
+ "name": "Unused variable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0613",
+ "name": "Unused argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0614",
+ "name": "Unused import from wildcard import",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0621",
+ "name": "Redefining name from outer scope",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0622",
+ "name": "Redefining built-in",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0623",
+ "name": "Redefining name in exception handler",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0631",
+ "name": "Using possibly undefined loop variable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0632",
+ "name": "Possible unbalanced tuple unpacking",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0633",
+ "name": "Attempting to unpack a non-sequence",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0640",
+ "name": "Cell variable defined in loop",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0641",
+ "name": "Possibly unused variable",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0642",
+ "name": "Invalid assignment in method",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0701",
+ "name": "Raising a string exception",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0702",
+ "name": "No exception type(s) specified",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0703",
+ "name": "Catching too general exception",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0704",
+ "name": "Except doesn't do anything",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0705",
+ "name": "Catching previously caught exception type",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0706",
+ "name": "The except handler raises immediately",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0710",
+ "name": "Exception doesn't inherit from standard \"Exception\" class",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0711",
+ "name": "Exception to catch is the result of a binary operation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0712",
+ "name": "Implicit unpacking of exceptions is not supported in Python 3",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0715",
+ "name": "Exception arguments suggest string formatting might be intended",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W0716",
+ "name": "Invalid exception operation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1001",
+ "name": "Use of \"property\" on an old style class",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1111",
+ "name": "Assigning to function call which only returns None",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1113",
+ "name": "Keyword argument before variable positional arguments list",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1201",
+ "name": "Specify string format arguments as logging function parameters",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1202",
+ "name": "Logging format interpolation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1203",
+ "name": "Usage of % formatting in logging functions",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1300",
+ "name": "Format string dictionary key should be a string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1301",
+ "name": "Unused key in format string dictionary",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1302",
+ "name": "Invalid format string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1303",
+ "name": "Missing keyword argument for format string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1304",
+ "name": "Unused format argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1305",
+ "name": "Format string contains both automatic field numbering and manual field specification",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1306",
+ "name": "Missing format attribute",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1307",
+ "name": "Using invalid lookup key in format specifier",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1308",
+ "name": "Duplicate string formatting argument",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1401",
+ "name": "Anomalous backslash escape",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1402",
+ "name": "Anomalous Unicode escape in byte string",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1403",
+ "name": "Implicit string concatenation",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1501",
+ "name": "Invalid mode for open",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1502",
+ "name": "Using datetime.time in a boolean context.",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1503",
+ "name": "Redundant unittest assert",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1505",
+ "name": "Using deprecated method",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1506",
+ "name": "threading.Thread needs the target function",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1507",
+ "name": "Using copy.copy(os.environ). Use os.environ.copy() instead.",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1508",
+ "name": "Invalid type in env manipulation functions",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1509",
+ "name": "Using preexec_fn keyword which may be unsafe in the presence of threads",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1601",
+ "name": "apply built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1602",
+ "name": "basestring built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1603",
+ "name": "buffer built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1604",
+ "name": "cmp built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1605",
+ "name": "coerce built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1606",
+ "name": "execfile built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1607",
+ "name": "file built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1608",
+ "name": "long built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1609",
+ "name": "raw_input built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1610",
+ "name": "reduce built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1611",
+ "name": "StandardError built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1612",
+ "name": "unicode built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1613",
+ "name": "xrange built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1614",
+ "name": "__coerce__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1615",
+ "name": "__delslice__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1616",
+ "name": "__getslice__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1617",
+ "name": "__setslice__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1618",
+ "name": "import missing `from __future__ import absolute_import`",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1619",
+ "name": "division w/o __future__ statement",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1620",
+ "name": "Calling a dict.iter*() method",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1621",
+ "name": "Calling a dict.view*() method",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1622",
+ "name": "Called a next() method on an object",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1623",
+ "name": "Assigning to a class's __metaclass__ attribute",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1624",
+ "name": "Indexing exceptions will not work on Python 3",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1625",
+ "name": "Raising a string exception",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1626",
+ "name": "reload built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1627",
+ "name": "__oct__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1628",
+ "name": "__hex__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1629",
+ "name": "__nonzero__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1630",
+ "name": "__cmp__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1632",
+ "name": "input built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1633",
+ "name": "round built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1634",
+ "name": "intern built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1635",
+ "name": "unichr built-in referenced",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1636",
+ "name": "map built-in referenced when not iterating",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1637",
+ "name": "zip built-in referenced when not iterating",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1638",
+ "name": "range built-in referenced when not iterating",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1639",
+ "name": "filter built-in referenced when not iterating",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1640",
+ "name": "Using the cmp argument for list.sort / sorted",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1641",
+ "name": "Implementing __eq__ without also implementing __hash__",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1642",
+ "name": "__div__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1643",
+ "name": "__idiv__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1644",
+ "name": "__rdiv__ method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1645",
+ "name": "Exception.message removed in Python 3",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1646",
+ "name": "non-text encoding used in str.decode",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1647",
+ "name": "sys.maxint removed in Python 3",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1649",
+ "name": "Accessing a deprecated function on the string module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1650",
+ "name": "Using str.translate with deprecated deletechars parameters",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1651",
+ "name": "Accessing a deprecated function on the itertools module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1652",
+ "name": "Accessing a deprecated fields on the types module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1653",
+ "name": "next method defined",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1654",
+ "name": "dict.items referenced when not iterating",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1655",
+ "name": "dict.keys referenced when not iterating",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1656",
+ "name": "dict.values referenced when not iterating",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1657",
+ "name": "Accessing a removed attribute on the operator module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1658",
+ "name": "Accessing a removed attribute on the urllib module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1659",
+ "name": "Accessing a removed xreadlines attribute",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1660",
+ "name": "Accessing a removed attribute on the sys module",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1661",
+ "name": "Using an exception object that was bound by an except handler",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ },
+ {
+ "key": "W1662",
+ "name": "Using a variable that was bound inside a comprehension",
+ "url": "http://pylint.pycqa.org/en/latest/"
+ }
+]
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java
index ef92e93ff1..78e2feb982 100644
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java
+++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/PythonPluginTest.java
@@ -35,11 +35,11 @@ public class PythonPluginTest {
@Test
public void testGetExtensions() {
- Version v74 = Version.create(7, 9);
- SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(v74, SonarQubeSide.SERVER, SonarEdition.DEVELOPER);
- assertThat(extensions(runtime)).hasSize(18);
+ Version v79 = Version.create(7, 9);
+ SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(v79, SonarQubeSide.SERVER, SonarEdition.DEVELOPER);
+ assertThat(extensions(runtime)).hasSize(21);
assertThat(extensions(runtime)).contains(DefaultAnalysisWarningsWrapper.class);
- assertThat(extensions(SonarRuntimeImpl.forSonarLint(v74))).hasSize(5);
+ assertThat(extensions(SonarRuntimeImpl.forSonarLint(v79))).hasSize(5);
}
private static List extensions(SonarRuntime runtime) {
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRulesDefinitionTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRulesDefinitionTest.java
new file mode 100644
index 0000000000..adeb1c617d
--- /dev/null
+++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintRulesDefinitionTest.java
@@ -0,0 +1,52 @@
+/*
+ * SonarQube Python Plugin
+ * Copyright (C) 2011-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.python.pylint;
+
+import org.junit.Test;
+import org.sonar.api.server.rule.RulesDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class PylintRulesDefinitionTest {
+
+ @Test
+ public void pylint_external_repository() {
+ RulesDefinition.Context context = new RulesDefinition.Context();
+ PylintRulesDefinition rulesDefinition = new PylintRulesDefinition();
+ rulesDefinition.define(context);
+
+ assertThat(context.repositories()).hasSize(1);
+ RulesDefinition.Repository repository = context.repository("external_pylint");
+ assertThat(repository).isNotNull();
+ assertThat(repository.name()).isEqualTo("Pylint");
+ assertThat(repository.language()).isEqualTo("py");
+ assertThat(repository.isExternal()).isTrue();
+ assertThat(repository.rules().size()).isEqualTo(370);
+
+ RulesDefinition.Rule rule = repository.rule("C0121");
+ assertThat(rule).isNotNull();
+ assertThat(rule.name()).isEqualTo("Singleton comparison");
+ assertThat(rule.htmlDescription()).isEqualTo("See description of Pylint rule C0121 at " +
+ "the Pylint website.");
+ assertThat(rule.debtRemediationFunction().type().name()).isEqualTo("CONSTANT_ISSUE");
+ assertThat(rule.debtRemediationFunction().baseEffort()).isEqualTo("5min");
+ assertThat(rule.tags()).isEmpty();
+ }
+}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
new file mode 100644
index 0000000000..560cdb0265
--- /dev/null
+++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
@@ -0,0 +1,240 @@
+/*
+ * SonarQube Python Plugin
+ * Copyright (C) 2011-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.plugins.python.pylint;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.SonarEdition;
+import org.sonar.api.SonarQubeSide;
+import org.sonar.api.batch.fs.InputFile;
+import org.sonar.api.batch.fs.TextRange;
+import org.sonar.api.batch.fs.internal.TestInputFileBuilder;
+import org.sonar.api.batch.rule.Severity;
+import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor;
+import org.sonar.api.batch.sensor.internal.SensorContextTester;
+import org.sonar.api.batch.sensor.issue.ExternalIssue;
+import org.sonar.api.batch.sensor.issue.IssueLocation;
+import org.sonar.api.internal.SonarRuntimeImpl;
+import org.sonar.api.rules.RuleType;
+import org.sonar.api.utils.Version;
+import org.sonar.api.utils.log.LogTester;
+import org.sonar.api.utils.log.LoggerLevel;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class PylintSensorTest {
+
+ private static final String PYLINT_FILE = "python-project:pylint/file1.py";
+ private static final String PYLINT_REPORT_DEFAULT_FORMAT = "pylint_report_default_format.txt";
+ private static final String PYLINT_REPORT_NO_COLUMN = "pylint_report_no_column.txt";
+
+ private static final Path PROJECT_DIR = Paths.get("src", "test", "resources", "org", "sonar", "plugins", "python", "pylint");
+
+ private static PylintSensor pylintSensor = new PylintSensor();
+
+ @Rule
+ public LogTester logTester = new LogTester();
+
+ @Test
+ public void test_descriptor() {
+ DefaultSensorDescriptor sensorDescriptor = new DefaultSensorDescriptor();
+ pylintSensor.describe(sensorDescriptor);
+ assertThat(sensorDescriptor.name()).isEqualTo("Import of Pylint issues");
+ assertThat(sensorDescriptor.languages()).containsOnly("py");
+ assertThat(sensorDescriptor.configurationPredicate()).isNotNull();
+ assertNoErrorWarnLogs(logTester);
+ }
+
+ @Test
+ public void issues_default_format() throws IOException {
+ List externalIssues = executeSensorImporting(7, 9, PYLINT_REPORT_DEFAULT_FORMAT);
+ assertThat(externalIssues).hasSize(10);
+
+ ExternalIssue first = externalIssues.get(0);
+ assertThat(first.ruleKey()).hasToString("external_pylint:C0114");
+ assertThat(first.type()).isEqualTo(RuleType.CODE_SMELL);
+ assertThat(first.severity()).isEqualTo(Severity.MAJOR);
+ IssueLocation firstPrimaryLoc = first.primaryLocation();
+ assertThat(firstPrimaryLoc.inputComponent().key()).isEqualTo(PYLINT_FILE);
+ assertThat(firstPrimaryLoc.message())
+ .isEqualTo("Missing module docstring (missing-module-docstring)");
+ TextRange firstTextRange = firstPrimaryLoc.textRange();
+ assertThat(firstTextRange).isNotNull();
+ assertThat(firstTextRange.start().line()).isEqualTo(1);
+ assertThat(firstTextRange.start().lineOffset()).isZero();
+ assertThat(firstTextRange.end().line()).isEqualTo(1);
+ assertThat(firstTextRange.end().lineOffset()).isEqualTo(1);
+
+ // Issue on column >= last column is reported on whole line instead
+ ExternalIssue last = externalIssues.get(9);
+ IssueLocation lastPrimaryLoc = last.primaryLocation();
+ TextRange lastTextRange = lastPrimaryLoc.textRange();
+ assertThat(lastTextRange).isNotNull();
+ assertThat(lastTextRange.start().line()).isEqualTo(1);
+ assertThat(lastTextRange.start().lineOffset()).isZero();
+ assertThat(lastTextRange.end().line()).isEqualTo(1);
+ assertThat(lastTextRange.end().lineOffset()).isEqualTo(13);
+
+ assertNoErrorWarnLogs(logTester);
+ }
+
+ @Test
+ public void issues_no_column_info() throws IOException {
+ List externalIssues = executeSensorImporting(7, 9, PYLINT_REPORT_NO_COLUMN);
+ assertThat(externalIssues).hasSize(3);
+
+ ExternalIssue first = externalIssues.get(0);
+ assertThat(first.ruleKey()).hasToString("external_pylint:C0111");
+ assertThat(first.type()).isEqualTo(RuleType.CODE_SMELL);
+ assertThat(first.severity()).isEqualTo(Severity.MAJOR);
+ IssueLocation firstPrimaryLoc = first.primaryLocation();
+ assertThat(firstPrimaryLoc.inputComponent().key()).isEqualTo(PYLINT_FILE);
+ assertThat(firstPrimaryLoc.message())
+ .isEqualTo("Missing module docstring");
+ TextRange firstTextRange = firstPrimaryLoc.textRange();
+ assertThat(firstTextRange).isNotNull();
+ assertThat(firstTextRange.start().line()).isEqualTo(1);
+ assertThat(firstTextRange.start().lineOffset()).isZero();
+ assertThat(firstTextRange.end().line()).isEqualTo(1);
+ assertThat(firstTextRange.end().lineOffset()).isEqualTo(13);
+
+ ExternalIssue second = externalIssues.get(1);
+ assertThat(second.ruleKey()).hasToString("external_pylint:C0103");
+ assertThat(second.type()).isEqualTo(RuleType.CODE_SMELL);
+ assertThat(second.severity()).isEqualTo(Severity.MAJOR);
+ IssueLocation secondPrimaryLoc = second.primaryLocation();
+ assertThat(secondPrimaryLoc.inputComponent().key()).isEqualTo(PYLINT_FILE);
+ assertThat(secondPrimaryLoc.message()).isEqualTo("Invalid argument name \"n\"");
+ TextRange secondTextRange = secondPrimaryLoc.textRange();
+ assertThat(secondTextRange).isNotNull();
+ assertThat(secondTextRange.start().line()).isEqualTo(1);
+ assertThat(secondTextRange.start().lineOffset()).isZero();
+ assertThat(secondTextRange.end().line()).isEqualTo(1);
+ assertThat(secondTextRange.end().lineOffset()).isEqualTo(13);
+
+ ExternalIssue third = externalIssues.get(2);
+ assertThat(third.ruleKey()).hasToString("external_pylint:C0111");
+ assertThat(third.type()).isEqualTo(RuleType.CODE_SMELL);
+ assertThat(third.severity()).isEqualTo(Severity.MAJOR);
+ IssueLocation thirdPrimaryLoc = third.primaryLocation();
+ assertThat(thirdPrimaryLoc.inputComponent().key()).isEqualTo(PYLINT_FILE);
+ assertThat(thirdPrimaryLoc.message()).isEqualTo("Missing function docstring");
+
+ assertNoErrorWarnLogs(logTester);
+ assertThat(onlyOneLogElement(logTester.logs(LoggerLevel.DEBUG)))
+ .isEqualTo("Cannot parse the line: ************* Module src.prod");
+ }
+
+ @Test
+ public void issues_other_formats() throws IOException {
+ List externalIssues = executeSensorImporting(7, 9, "pylint_brackets.txt");
+ assertThat(externalIssues).hasSize(10);
+ ExternalIssue first = externalIssues.get(0);
+ assertThat(first.ruleKey()).hasToString("external_pylint:E1300");
+ assertThat(first.type()).isEqualTo(RuleType.CODE_SMELL);
+ assertThat(first.severity()).isEqualTo(Severity.MAJOR);
+ IssueLocation firstPrimaryLoc = first.primaryLocation();
+ assertThat(firstPrimaryLoc.inputComponent().key()).isEqualTo(PYLINT_FILE);
+ assertThat(firstPrimaryLoc.message())
+ .isEqualTo("message");
+
+ externalIssues = executeSensorImporting(7, 9, "pylint_names_in_brackets.txt");
+ assertThat(externalIssues).hasSize(1);
+ first = externalIssues.get(0);
+ assertThat(first.ruleKey()).hasToString("external_pylint:C0111");
+ assertThat(first.type()).isEqualTo(RuleType.CODE_SMELL);
+ assertThat(first.severity()).isEqualTo(Severity.MAJOR);
+ firstPrimaryLoc = first.primaryLocation();
+ assertThat(firstPrimaryLoc.inputComponent().key()).isEqualTo(PYLINT_FILE);
+ assertThat(firstPrimaryLoc.message())
+ .isEqualTo("Missing docstring");
+ }
+
+ @Test
+ public void no_issues_unknown_files() throws IOException {
+ List externalIssues = executeSensorImporting(7, 9, "pylint_report_unknown_files.txt");
+ assertThat(externalIssues).isEmpty();
+ assertThat(onlyOneLogElement(logTester.logs(LoggerLevel.WARN))).hasToString("Failed to resolve 1 file path(s) in Pylint report. " +
+ "No issues imported related to file(s): pylint/unknown_file.py");
+ }
+
+ @Test
+ public void no_issues_with_invalid_report_path() throws IOException {
+ List externalIssues = executeSensorImporting(7, 9, "invalid-path.txt");
+ assertThat(externalIssues).isEmpty();
+ assertThat(onlyOneLogElement(logTester.logs(LoggerLevel.ERROR)))
+ .startsWith("No issues information will be saved as the report file '")
+ .contains("invalid-path.txt' can't be read.");
+ }
+
+ private static List executeSensorImporting(int majorVersion, int minorVersion, @Nullable String fileName) throws IOException {
+ Path baseDir = PROJECT_DIR.getParent();
+ SensorContextTester context = SensorContextTester.create(baseDir);
+ try (Stream fileStream = Files.list(PROJECT_DIR)) {
+ fileStream.forEach(file -> addFileToContext(context, baseDir, file));
+ context.setRuntime(SonarRuntimeImpl.forSonarQube(Version.create(majorVersion, minorVersion), SonarQubeSide.SERVER, SonarEdition.DEVELOPER));
+ if (fileName != null) {
+ String path = PROJECT_DIR.resolve(fileName).toAbsolutePath().toString();
+ context.settings().setProperty("sonar.python.pylint.reportPaths", path);
+ }
+ pylintSensor.execute(context);
+ return new ArrayList<>(context.allExternalIssues());
+ }
+ }
+
+ private static void addFileToContext(SensorContextTester context, Path projectDir, Path file) {
+ try {
+ String projectId = projectDir.getFileName().toString() + "-project";
+ context.fileSystem().add(TestInputFileBuilder.create(projectId, projectDir.toFile(), file.toFile())
+ .setCharset(UTF_8)
+ .setLanguage(language(file))
+ .setContents(new String(Files.readAllBytes(file), UTF_8))
+ .setType(InputFile.Type.MAIN)
+ .build());
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private static String language(Path file) {
+ String path = file.toString();
+ return path.substring(path.lastIndexOf('.') + 1);
+ }
+
+ public static String onlyOneLogElement(List elements) {
+ assertThat(elements).hasSize(1);
+ return elements.get(0);
+ }
+
+ public static void assertNoErrorWarnLogs(LogTester logTester) {
+ assertThat(logTester.logs(LoggerLevel.ERROR)).isEmpty();
+ assertThat(logTester.logs(LoggerLevel.WARN)).isEmpty();
+ }
+
+}
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/file1.py b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/file1.py
new file mode 100644
index 0000000000..b14d5f7e3e
--- /dev/null
+++ b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/file1.py
@@ -0,0 +1,30 @@
+def myfunc():
+ def unused() -> str:
+ smth = 42
+ max = 24
+ if smth == smth:
+ print("Hello?")
+ return smth
+
+ print("Hello!")
+
+
+def my_other_func():
+ my_list = []
+ if my_list is []:
+ print("Impossible!")
+ my_tuple = (1, 2)
+ try:
+ my_tuple + my_list
+ except TypeError:
+ print("Hello there!")
+ return 24
+
+
+def main():
+ myfunc()
+ my_other_func()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint-report-unknown-rules.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint-report-unknown-rules.txt
deleted file mode 100644
index 5a8f103eb9..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint-report-unknown-rules.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-************* Module src.prod
-src/file1.py:1: [C0111(missing-docstring), ] Missing module docstring
-src/file1.py:1: [C0103(invalid-name), factorial] Invalid argument name "n"
-src/file1.py:1: [C0111(missing-docstring), factorial] Missing function docstring
-src/file1.py:1: [C8888(unknown-rule1), ] This rule is not defined 1
-src/file1.py:1: [C9999(unknown-rule2), ] This rule is not defined 2
-src/file1.py:1: [C9999(unknown-rule2), ] This rule is not defined 2
\ No newline at end of file
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint-report.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint-report.txt
deleted file mode 100644
index 09c32309a4..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint-report.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-************* Module src.prod
-src/file1.py:1: [C0111(missing-docstring), ] Missing module docstring
-src/file1.py:1: [C0103(invalid-name), factorial] Invalid argument name "n"
-src/file1.py:1: [C0111(missing-docstring), factorial] Missing function docstring
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_brackets.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_brackets.txt
new file mode 100644
index 0000000000..fbc5ff9f90
--- /dev/null
+++ b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_brackets.txt
@@ -0,0 +1,10 @@
+pylint/file1.py:1: [E1300] message
+pylint/file1.py:1: [E1301] message
+pylint/file1.py:1: [E1302] message
+pylint/file1.py:1: [E1303] message
+pylint/file1.py:1: [E1304] message
+pylint/file1.py:1: [E1305] message
+pylint/file1.py:1: [E1306] message
+pylint/file1.py:1: [W1201] message
+pylint/file1.py:1: [W1300] message
+pylint/file1.py:1: [W1301] message
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_names_in_brackets.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_names_in_brackets.txt
new file mode 100644
index 0000000000..38fcd1767f
--- /dev/null
+++ b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_names_in_brackets.txt
@@ -0,0 +1 @@
+pylint/file1.py:1: [C0111] Missing docstring
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_default_format.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_default_format.txt
new file mode 100644
index 0000000000..bba1d554d2
--- /dev/null
+++ b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_default_format.txt
@@ -0,0 +1,14 @@
+************* Module src.main
+pylint/file1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
+pylint/file1.py:1:0: C0116: Missing function or method docstring (missing-function-docstring)
+pylint/file1.py:4:8: W0622: Redefining built-in 'max' (redefined-builtin)
+pylint/file1.py:5:11: R0124: Redundant comparison - smth == smth (comparison-with-itself)
+pylint/file1.py:4:8: W0612: Unused variable 'max' (unused-variable)
+pylint/file1.py:2:4: W0612: Unused variable 'unused' (unused-variable)
+pylint/file1.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
+pylint/file1.py:14:7: R0123: Comparison to literal (literal-comparison)
+pylint/file1.py:24:0: C0116: Missing function or method docstring (missing-function-docstring)
+
+pylint/file1.py:1:13: TEST1: No problem when issue is on last column
+------------------------------------------------------------------
+Your code has been rated at 6.09/10 (previous run: 6.09/10, +0.00)
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_no_column.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_no_column.txt
new file mode 100644
index 0000000000..8b4ab2d9e4
--- /dev/null
+++ b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_no_column.txt
@@ -0,0 +1,4 @@
+************* Module src.prod
+pylint/file1.py:1: [C0111(missing-docstring), ] Missing module docstring
+pylint/file1.py:1: [C0103(invalid-name), factorial] Invalid argument name "n"
+pylint/file1.py:1: [C0111(missing-docstring), factorial] Missing function docstring
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_unknown_files.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_unknown_files.txt
new file mode 100644
index 0000000000..5efa46a55e
--- /dev/null
+++ b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/pylint_report_unknown_files.txt
@@ -0,0 +1,13 @@
+************* Module src.main
+pylint/unknown_file.py:1:0: C0114: Missing module docstring (missing-module-docstring)
+pylint/unknown_file.py:1:0: C0116: Missing function or method docstring (missing-function-docstring)
+pylint/unknown_file.py:4:8: W0622: Redefining built-in 'max' (redefined-builtin)
+pylint/unknown_file.py:5:11: R0124: Redundant comparison - smth == smth (comparison-with-itself)
+pylint/unknown_file.py:4:8: W0612: Unused variable 'max' (unused-variable)
+pylint/unknown_file.py:2:4: W0612: Unused variable 'unused' (unused-variable)
+pylint/unknown_file.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
+pylint/unknown_file.py:14:7: R0123: Comparison to literal (literal-comparison)
+pylint/unknown_file.py:24:0: C0116: Missing function or method docstring (missing-function-docstring)
+
+------------------------------------------------------------------
+Your code has been rated at 6.09/10 (previous run: 6.09/10, +0.00)
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output.txt
deleted file mode 100644
index 3c14fc41ad..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-code_chunks.py:1: [C0111] Missing docstring
-code_chunks.py:1: [C0111, if_else] Missing docstring
-code_chunks.py:7: [C0111, if_elif_else] Missing docstring
-code_chunks.py:15: [C0111, if_compl_cond1] Missing docstring
-code_chunks.py:21: [C0111, if_compl_cond2] Missing docstring
-code_chunks.py:27: [C0111, for_else] Missing docstring
-code_chunks.py:28: [C0103, for_else] Invalid name "x" (should match [a-z_][a-z0-9_]{2,30}$)
-code_chunks.py:28: [W0612, for_else] Unused variable 'x'
-code_chunks.py:33: [C0111, while_comp_cond] Missing docstring
-code_chunks.py:37: [C0111, while_else] Missing docstring
-code_chunks.py:43: [C0111, while_else_compl_cond1] Missing docstring
-code_chunks.py:49: [C0111, while_else_compl_cond2] Missing docstring
-code_chunks.py:55: [C0111, while_else_compl_cond3] Missing docstring
-code_chunks.py:61: [C0111, list_compr] Missing docstring
-code_chunks.py:62: [W0104, list_compr] Statement seems to have no effect
-code_chunks.py:64: [C0111, list_compr_filter] Missing docstring
-code_chunks.py:65: [W0104, list_compr_filter] Statement seems to have no effect
-code_chunks.py:67: [C0111, gen_expr] Missing docstring
-code_chunks.py:68: [W0104, gen_expr] Statement seems to have no effect
-code_chunks.py:70: [C0111, gen_expr_filter] Missing docstring
-code_chunks.py:71: [W0104, gen_expr_filter] Statement seems to have no effect
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_new_format.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_new_format.txt
deleted file mode 100644
index 3332a7553d..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_new_format.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-code_chunks.py:1: [C0111(missing-docstring)] Missing docstring
-
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_newids.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_newids.txt
deleted file mode 100644
index 2ec21efe4d..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_newids.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-code_chunks.py:1: [E1300] message
-code_chunks.py:1: [E1301] message
-code_chunks.py:1: [E1302] message
-code_chunks.py:1: [E1303] message
-code_chunks.py:1: [E1304] message
-code_chunks.py:1: [E1305] message
-code_chunks.py:1: [E1306] message
-code_chunks.py:1: [W1201] message
-code_chunks.py:1: [W1300] message
-code_chunks.py:1: [W1301] message
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_oldids.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_oldids.txt
deleted file mode 100644
index d30cf0ac70..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_oldids.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-code_chunks.py:1: [E9900] message
-code_chunks.py:1: [E9901] message
-code_chunks.py:1: [E9902] message
-code_chunks.py:1: [E9903] message
-code_chunks.py:1: [E9904] message
-code_chunks.py:1: [E9905] message
-code_chunks.py:1: [E9906] message
-code_chunks.py:1: [W6501] message
-code_chunks.py:1: [W9900] message
-code_chunks.py:1: [W9901] message
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_with_win_paths.txt b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_with_win_paths.txt
deleted file mode 100644
index 268c5254ff..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/sample_pylint_output_with_win_paths.txt
+++ /dev/null
@@ -1 +0,0 @@
-C:\code_chunks.py:1: [C0111] Missing docstring
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/src/file1.py b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/src/file1.py
deleted file mode 100644
index 11b15b1a45..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/src/file1.py
+++ /dev/null
@@ -1 +0,0 @@
-print("hello")
diff --git a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/src/file2.py b/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/src/file2.py
deleted file mode 100644
index 0239905611..0000000000
--- a/sonar-python-plugin/src/test/resources/org/sonar/plugins/python/pylint/src/file2.py
+++ /dev/null
@@ -1 +0,0 @@
-print("hello2")
From 8471488d1232be84abc17ff255d9930e7b300f3f Mon Sep 17 00:00:00 2001
From: Guillaume Dequenne
Date: Thu, 9 Jul 2020 16:45:43 +0200
Subject: [PATCH 4/5] SONARPY-754 Support old reportPath property for Pylint
import (#809)
---
.../python/it/plugin/PylintReportTest.java | 22 +++++++---
.../plugins/python/ExternalIssuesSensor.java | 11 ++++-
.../plugins/python/bandit/BanditSensor.java | 7 +++
.../plugins/python/flake8/Flake8Sensor.java | 6 +++
.../plugins/python/pylint/PylintSensor.java | 6 +++
.../python/bandit/BanditSensorTest.java | 11 +++++
.../python/flake8/Flake8SensorTest.java | 11 +++++
.../python/pylint/PylintSensorTest.java | 44 +++++++++++++++----
8 files changed, 102 insertions(+), 16 deletions(-)
diff --git a/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/PylintReportTest.java b/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/PylintReportTest.java
index 153294b9d1..f63cf55f2a 100644
--- a/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/PylintReportTest.java
+++ b/its/plugin/it-python-plugin-test/src/test/java/com/sonar/python/it/plugin/PylintReportTest.java
@@ -36,38 +36,46 @@
public class PylintReportTest {
private static final String PROJECT = "pylint_project";
+ private static final String DEFAULT_PROPERTY = "sonar.python.pylint.reportPaths";
+ private static final String LEGACY_PROPERTY = "sonar.python.pylint.reportPath";
@ClassRule
public static final Orchestrator ORCHESTRATOR = Tests.ORCHESTRATOR;
@Test
public void import_report() {
- analyseProjectWithReport("pylint-report.txt");
+ analyseProjectWithReport(DEFAULT_PROPERTY, "pylint-report.txt");
+ assertThat(issues()).hasSize(4);
+ }
+
+ @Test
+ public void import_report_legacy_key() {
+ analyseProjectWithReport(LEGACY_PROPERTY, "pylint-report.txt");
assertThat(issues()).hasSize(4);
}
@Test
public void missing_report() {
- analyseProjectWithReport("missing");
+ analyseProjectWithReport(DEFAULT_PROPERTY, "missing");
assertThat(issues()).isEmpty();
}
@Test
public void invalid_report() {
- BuildResult result = analyseProjectWithReport("invalid.txt");
+ BuildResult result = analyseProjectWithReport(DEFAULT_PROPERTY, "invalid.txt");
assertThat(result.getLogs()).contains("Cannot parse the line: trash");
assertThat(issues()).isEmpty();
}
@Test
public void unknown_rule() {
- BuildResult result = analyseProjectWithReport("rule-unknown.txt");
+ BuildResult result = analyseProjectWithReport(DEFAULT_PROPERTY, "rule-unknown.txt");
assertThat(issues()).hasSize(4);
}
@Test
public void multiple_reports() {
- analyseProjectWithReport("pylint-report.txt, rule-unknown.txt");
+ analyseProjectWithReport(DEFAULT_PROPERTY, "pylint-report.txt, rule-unknown.txt");
assertThat(issues()).hasSize(8);
}
@@ -75,7 +83,7 @@ private static List issues() {
return newWsClient().issues().search(new SearchRequest().setProjects(singletonList(PROJECT))).getIssuesList();
}
- private static BuildResult analyseProjectWithReport(String reportPaths) {
+ private static BuildResult analyseProjectWithReport(String property, String reportPaths) {
ORCHESTRATOR.resetData();
ORCHESTRATOR.getServer().provisionProject(PROJECT, PROJECT);
ORCHESTRATOR.getServer().associateProjectToQualityProfile(PROJECT, "py", "no_rule");
@@ -84,7 +92,7 @@ private static BuildResult analyseProjectWithReport(String reportPaths) {
SonarScanner.create()
.setDebugLogs(true)
.setProjectDir(new File("projects/pylint_project"))
- .setProperty("sonar.python.pylint.reportPaths", reportPaths));
+ .setProperty(property, reportPaths));
}
}
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java
index 42f384262c..39567a5ba1 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/ExternalIssuesSensor.java
@@ -33,8 +33,10 @@
import org.sonar.api.batch.sensor.SensorDescriptor;
import org.sonar.api.batch.sensor.issue.NewExternalIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+import org.sonar.api.config.Configuration;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.log.Logger;
+import org.sonar.plugins.python.pylint.PylintSensor;
import org.sonarsource.analyzer.commons.ExternalReportProvider;
import org.sonarsource.analyzer.commons.internal.json.simple.parser.ParseException;
@@ -42,11 +44,12 @@ public abstract class ExternalIssuesSensor implements Sensor {
private static final int MAX_LOGGED_FILE_NAMES = 20;
private static final Long DEFAULT_CONSTANT_DEBT_MINUTES = 5L;
+ protected static final String PYLINT_LEGACY_KEY = "sonar.python.pylint.reportPath";
@Override
public void describe(SensorDescriptor descriptor) {
descriptor
- .onlyWhenConfiguration(conf -> conf.hasKey(reportPathKey()))
+ .onlyWhenConfiguration(this::shouldExecute)
.onlyOnLanguage(Python.KEY)
.name("Import of " + linterName() + " issues");
}
@@ -55,6 +58,10 @@ public void describe(SensorDescriptor descriptor) {
public void execute(SensorContext context) {
Set unresolvedInputFiles = new HashSet<>();
List reportFiles = ExternalReportProvider.getReportFiles(context, reportPathKey());
+ if (reportFiles.isEmpty() && context.config().hasKey(PYLINT_LEGACY_KEY)) {
+ reportFiles = ExternalReportProvider.getReportFiles(context, PYLINT_LEGACY_KEY);
+ logger().warn("The use of '{}' is deprecated. Please use the '{}' property instead.", PYLINT_LEGACY_KEY, PylintSensor.REPORT_PATH_KEY);
+ }
reportFiles.forEach(report -> importExternalReport(report, context, unresolvedInputFiles));
logUnresolvedInputFiles(unresolvedInputFiles);
}
@@ -113,6 +120,8 @@ protected void saveIssue(SensorContext context, TextReportReader.Issue issue, Se
protected abstract void importReport(File reportPath, SensorContext context, Set unresolvedInputFiles) throws IOException, ParseException;
+ protected abstract boolean shouldExecute(Configuration conf);
+
protected abstract String linterName();
protected abstract String reportPathKey();
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/bandit/BanditSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/bandit/BanditSensor.java
index 6c3cf60806..82ea7a182e 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/bandit/BanditSensor.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/bandit/BanditSensor.java
@@ -29,6 +29,7 @@
import org.sonar.api.batch.sensor.SensorContext;
import org.sonar.api.batch.sensor.issue.NewExternalIssue;
import org.sonar.api.batch.sensor.issue.NewIssueLocation;
+import org.sonar.api.config.Configuration;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.RuleType;
import org.sonar.api.utils.Version;
@@ -58,6 +59,7 @@ protected void importReport(File reportPath, SensorContext context, Set
BanditJsonReportReader.read(in, issue -> saveIssue(context, issue, unresolvedInputFiles, engineIdIsSupported));
}
+
private static void saveIssue(SensorContext context, Issue issue, Set unresolvedInputFiles, boolean engineIdIsSupported) {
if (isEmpty(issue.ruleKey) || isEmpty(issue.filePath) || isEmpty(issue.message)) {
LOG.debug("Missing information for ruleKey:'{}', filePath:'{}', message:'{}'", issue.ruleKey, issue.filePath, issue.message);
@@ -106,6 +108,11 @@ private static Severity toSonarQubeSeverity(String severity, String confidence)
}
}
+ @Override
+ protected boolean shouldExecute(Configuration conf) {
+ return conf.hasKey(REPORT_PATH_KEY);
+ }
+
@Override
protected String linterName() {
return LINTER_NAME;
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8Sensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8Sensor.java
index 365b6af6b6..28571ba469 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8Sensor.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/flake8/Flake8Sensor.java
@@ -24,6 +24,7 @@
import java.util.List;
import java.util.Set;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.plugins.python.ExternalIssuesSensor;
@@ -44,6 +45,11 @@ protected void importReport(File reportPath, SensorContext context, Set
issues.forEach(i -> saveIssue(context, i, unresolvedInputFiles, LINTER_KEY));
}
+ @Override
+ protected boolean shouldExecute(Configuration conf) {
+ return conf.hasKey(REPORT_PATH_KEY);
+ }
+
@Override
protected String linterName() {
return LINTER_NAME;
diff --git a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
index 1e808985eb..0a229b8c35 100644
--- a/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
+++ b/sonar-python-plugin/src/main/java/org/sonar/plugins/python/pylint/PylintSensor.java
@@ -24,6 +24,7 @@
import java.util.List;
import java.util.Set;
import org.sonar.api.batch.sensor.SensorContext;
+import org.sonar.api.config.Configuration;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.plugins.python.ExternalIssuesSensor;
@@ -44,6 +45,11 @@ protected void importReport(File reportPath, SensorContext context, Set
issues.forEach(i -> saveIssue(context, i, unresolvedInputFiles, LINTER_KEY));
}
+ @Override
+ protected boolean shouldExecute(Configuration conf) {
+ return conf.hasKey(REPORT_PATH_KEY) || conf.hasKey(PYLINT_LEGACY_KEY);
+ }
+
@Override
protected String reportPathKey() {
return REPORT_PATH_KEY;
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/bandit/BanditSensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/bandit/BanditSensorTest.java
index 324a0350c2..6e49478599 100644
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/bandit/BanditSensorTest.java
+++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/bandit/BanditSensorTest.java
@@ -52,6 +52,7 @@ public class BanditSensorTest {
private static final String BANDIT_FILE = "python-project:bandit/file1.py";
private static final String BANDIT_B413 = "external_bandit:B413";
+ private static final String BANDIT_PROPERTY = "sonar.python.bandit.reportPaths";
private static final String BANDIT_REPORT_JSON = "bandit-report.json";
private static final Path PROJECT_DIR = Paths.get("src", "test", "resources", "org", "sonar", "plugins", "python", "bandit");
@@ -69,6 +70,16 @@ public void test_descriptor() {
assertThat(sensorDescriptor.languages()).containsOnly("py");
assertThat(sensorDescriptor.configurationPredicate()).isNotNull();
assertNoErrorWarnDebugLogs(logTester);
+
+ Path baseDir = PROJECT_DIR.getParent();
+ SensorContextTester context = SensorContextTester.create(baseDir);
+ context.settings().setProperty(BANDIT_PROPERTY, "path/to/report");
+ assertThat(sensorDescriptor.configurationPredicate().test(context.config())).isTrue();
+
+ context = SensorContextTester.create(baseDir);
+ context.settings().setProperty("sonar.python.bandit.reportPath", "path/to/report");
+ // No support of "reportPath" property for Bandit
+ assertThat(sensorDescriptor.configurationPredicate().test(context.config())).isFalse();
}
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/flake8/Flake8SensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/flake8/Flake8SensorTest.java
index 801c54abf0..37a8fec5c7 100644
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/flake8/Flake8SensorTest.java
+++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/flake8/Flake8SensorTest.java
@@ -53,6 +53,7 @@ public class Flake8SensorTest {
private static final String FLAKE8_FILE = "python-project:flake8/file1.py";
private static final String FLAKE8_F401 = "external_flake8:F401";
private static final String FLAKE_8_REPORT = "flake8-report.txt";
+ private static final String FLAKE_8_PROPERTY = "sonar.python.flake8.reportPaths";
private static final String FLAKE_8_REPORT_UNKNOWN_FILES = "flake8-report-unknown-files.txt";
private static final Path PROJECT_DIR = Paths.get("src", "test", "resources", "org", "sonar", "plugins", "python", "flake8");
@@ -70,6 +71,16 @@ public void test_descriptor() {
assertThat(sensorDescriptor.languages()).containsOnly("py");
assertThat(sensorDescriptor.configurationPredicate()).isNotNull();
assertNoErrorWarnDebugLogs(logTester);
+
+ Path baseDir = PROJECT_DIR.getParent();
+ SensorContextTester context = SensorContextTester.create(baseDir);
+ context.settings().setProperty(FLAKE_8_PROPERTY, "path/to/report");
+ assertThat(sensorDescriptor.configurationPredicate().test(context.config())).isTrue();
+
+ context = SensorContextTester.create(baseDir);
+ context.settings().setProperty("sonar.python.flake8.reportPath", "path/to/report");
+ // No support of "reportPath" property for Flake8
+ assertThat(sensorDescriptor.configurationPredicate().test(context.config())).isFalse();
}
@Test
diff --git a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
index 560cdb0265..eadccb485d 100644
--- a/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
+++ b/sonar-python-plugin/src/test/java/org/sonar/plugins/python/pylint/PylintSensorTest.java
@@ -53,6 +53,8 @@ public class PylintSensorTest {
private static final String PYLINT_FILE = "python-project:pylint/file1.py";
private static final String PYLINT_REPORT_DEFAULT_FORMAT = "pylint_report_default_format.txt";
private static final String PYLINT_REPORT_NO_COLUMN = "pylint_report_no_column.txt";
+ private static final String DEFAULT_PROPERTY = "sonar.python.pylint.reportPaths";
+ private static final String LEGACY_PROPERTY = "sonar.python.pylint.reportPath";
private static final Path PROJECT_DIR = Paths.get("src", "test", "resources", "org", "sonar", "plugins", "python", "pylint");
@@ -69,11 +71,25 @@ public void test_descriptor() {
assertThat(sensorDescriptor.languages()).containsOnly("py");
assertThat(sensorDescriptor.configurationPredicate()).isNotNull();
assertNoErrorWarnLogs(logTester);
+
+ Path baseDir = PROJECT_DIR.getParent();
+ SensorContextTester context = SensorContextTester.create(baseDir);
+ context.settings().setProperty(DEFAULT_PROPERTY, "path/to/report");
+ assertThat(sensorDescriptor.configurationPredicate().test(context.config())).isTrue();
+
+ context = SensorContextTester.create(baseDir);
+ context.settings().setProperty(LEGACY_PROPERTY, "path/to/report");
+ // Support of legacy "reportPath" property for Pylint
+ assertThat(sensorDescriptor.configurationPredicate().test(context.config())).isTrue();
+
+ context = SensorContextTester.create(baseDir);
+ context.settings().setProperty("random.key", "path/to/report");
+ assertThat(sensorDescriptor.configurationPredicate().test(context.config())).isFalse();
}
@Test
public void issues_default_format() throws IOException {
- List externalIssues = executeSensorImporting(7, 9, PYLINT_REPORT_DEFAULT_FORMAT);
+ List externalIssues = executeSensorImporting(7, 9, PYLINT_REPORT_DEFAULT_FORMAT, false);
assertThat(externalIssues).hasSize(10);
ExternalIssue first = externalIssues.get(0);
@@ -106,7 +122,7 @@ public void issues_default_format() throws IOException {
@Test
public void issues_no_column_info() throws IOException {
- List externalIssues = executeSensorImporting(7, 9, PYLINT_REPORT_NO_COLUMN);
+ List externalIssues = executeSensorImporting(7, 9, PYLINT_REPORT_NO_COLUMN, false);
assertThat(externalIssues).hasSize(3);
ExternalIssue first = externalIssues.get(0);
@@ -153,7 +169,7 @@ public void issues_no_column_info() throws IOException {
@Test
public void issues_other_formats() throws IOException {
- List externalIssues = executeSensorImporting(7, 9, "pylint_brackets.txt");
+ List externalIssues = executeSensorImporting(7, 9, "pylint_brackets.txt", false);
assertThat(externalIssues).hasSize(10);
ExternalIssue first = externalIssues.get(0);
assertThat(first.ruleKey()).hasToString("external_pylint:E1300");
@@ -164,7 +180,7 @@ public void issues_other_formats() throws IOException {
assertThat(firstPrimaryLoc.message())
.isEqualTo("message");
- externalIssues = executeSensorImporting(7, 9, "pylint_names_in_brackets.txt");
+ externalIssues = executeSensorImporting(7, 9, "pylint_names_in_brackets.txt", false);
assertThat(externalIssues).hasSize(1);
first = externalIssues.get(0);
assertThat(first.ruleKey()).hasToString("external_pylint:C0111");
@@ -178,7 +194,7 @@ public void issues_other_formats() throws IOException {
@Test
public void no_issues_unknown_files() throws IOException {
- List externalIssues = executeSensorImporting(7, 9, "pylint_report_unknown_files.txt");
+ List externalIssues = executeSensorImporting(7, 9, "pylint_report_unknown_files.txt", false);
assertThat(externalIssues).isEmpty();
assertThat(onlyOneLogElement(logTester.logs(LoggerLevel.WARN))).hasToString("Failed to resolve 1 file path(s) in Pylint report. " +
"No issues imported related to file(s): pylint/unknown_file.py");
@@ -186,14 +202,22 @@ public void no_issues_unknown_files() throws IOException {
@Test
public void no_issues_with_invalid_report_path() throws IOException {
- List externalIssues = executeSensorImporting(7, 9, "invalid-path.txt");
+ List externalIssues = executeSensorImporting(7, 9, "invalid-path.txt", false);
assertThat(externalIssues).isEmpty();
assertThat(onlyOneLogElement(logTester.logs(LoggerLevel.ERROR)))
.startsWith("No issues information will be saved as the report file '")
.contains("invalid-path.txt' can't be read.");
}
- private static List executeSensorImporting(int majorVersion, int minorVersion, @Nullable String fileName) throws IOException {
+ @Test
+ public void import_with_legacy_property() throws IOException {
+ List externalIssues = executeSensorImporting(7, 9, "pylint_brackets.txt", true);
+ assertThat(externalIssues).hasSize(10);
+ assertThat(onlyOneLogElement(logTester.logs())).hasToString("The use of 'sonar.python.pylint.reportPath' is deprecated." +
+ " Please use the 'sonar.python.pylint.reportPaths' property instead.");
+ }
+
+ private static List executeSensorImporting(int majorVersion, int minorVersion, @Nullable String fileName, boolean useLegacyKey) throws IOException {
Path baseDir = PROJECT_DIR.getParent();
SensorContextTester context = SensorContextTester.create(baseDir);
try (Stream fileStream = Files.list(PROJECT_DIR)) {
@@ -201,7 +225,11 @@ private static List executeSensorImporting(int majorVersion, int
context.setRuntime(SonarRuntimeImpl.forSonarQube(Version.create(majorVersion, minorVersion), SonarQubeSide.SERVER, SonarEdition.DEVELOPER));
if (fileName != null) {
String path = PROJECT_DIR.resolve(fileName).toAbsolutePath().toString();
- context.settings().setProperty("sonar.python.pylint.reportPaths", path);
+ if (useLegacyKey) {
+ context.settings().setProperty(LEGACY_PROPERTY, path);
+ } else {
+ context.settings().setProperty(DEFAULT_PROPERTY, path);
+ }
}
pylintSensor.execute(context);
return new ArrayList<>(context.allExternalIssues());
From 4817dcd0c0f2ae5884b85eaa049ad220b388e471 Mon Sep 17 00:00:00 2001
From: Guillaume Dequenne
Date: Tue, 14 Jul 2020 15:11:15 +0200
Subject: [PATCH 5/5] Remove old Pylint metadata
---
.../sonar/plugins/python/profile-default.xml | 729 ----
.../sonar/plugins/python/pylint/convert.py | 112 -
.../python/pylint/generate_rules_file.sh | 2 -
.../python/pylint/remediation-cost.csv | 370 --
.../org/sonar/plugins/python/pylint/rules.xml | 3507 -----------------
.../plugins/python/pylint/rules_generated.xml | 2563 ------------
6 files changed, 7283 deletions(-)
delete mode 100644 sonar-python-plugin/src/main/resources/org/sonar/plugins/python/profile-default.xml
delete mode 100755 sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/convert.py
delete mode 100755 sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/generate_rules_file.sh
delete mode 100644 sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/remediation-cost.csv
delete mode 100644 sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules.xml
delete mode 100644 sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules_generated.xml
diff --git a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/profile-default.xml b/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/profile-default.xml
deleted file mode 100644
index 5ba37f1485..0000000000
--- a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/profile-default.xml
+++ /dev/null
@@ -1,729 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Sonar way
- py
-
-
- Pylint
- E0001
- MAJOR
-
-
- Pylint
- E0011
- MAJOR
-
-
- Pylint
- E0012
- MAJOR
-
-
- Pylint
- E0100
- MAJOR
-
-
- Pylint
- E0101
- MAJOR
-
-
- Pylint
- E0102
- MAJOR
-
-
- Pylint
- E0103
- MAJOR
-
-
- Pylint
- E0104
- MAJOR
-
-
- Pylint
- E0105
- MAJOR
-
-
- Pylint
- E0106
- MAJOR
-
-
- Pylint
- E0107
- MAJOR
-
-
- Pylint
- E0202
- MAJOR
-
-
- Pylint
- E0203
- MAJOR
-
-
- Pylint
- E0211
- MAJOR
-
-
- Pylint
- E0213
- MAJOR
-
-
- Pylint
- E0221
- MAJOR
-
-
- Pylint
- E0222
- MAJOR
-
-
- Pylint
- E0501
- MAJOR
-
-
- Pylint
- E0502
- MAJOR
-
-
- Pylint
- E0503
- MAJOR
-
-
- Pylint
- E0601
- MAJOR
-
-
- Pylint
- E0602
- MAJOR
-
-
- Pylint
- E0611
- MAJOR
-
-
- Pylint
- E0701
- MAJOR
-
-
- Pylint
- E0702
- MAJOR
-
-
- Pylint
- E0710
- MAJOR
-
-
- Pylint
- E0711
- MAJOR
-
-
- Pylint
- E1001
- MAJOR
-
-
- Pylint
- E1002
- MAJOR
-
-
- Pylint
- E1003
- MAJOR
-
-
- Pylint
- E1101
- MAJOR
-
-
- Pylint
- E1102
- MAJOR
-
-
- Pylint
- E1103
- MAJOR
-
-
- Pylint
- E1111
- MAJOR
-
-
- Pylint
- E1120
- MAJOR
-
-
- Pylint
- E1121
- MAJOR
-
-
- Pylint
- E1122
- MAJOR
-
-
- Pylint
- E1123
- MAJOR
-
-
- Pylint
- E1124
- MAJOR
-
-
- Pylint
- E1300
- MAJOR
-
-
- Pylint
- E1301
- MAJOR
-
-
- Pylint
- E1302
- MAJOR
-
-
- Pylint
- E1303
- MAJOR
-
-
- Pylint
- E1304
- MAJOR
-
-
- Pylint
- E1305
- MAJOR
-
- Pylint
- E1306
- MAJOR
-
- Pylint
- F0001
- MAJOR
-
-
- Pylint
- F0002
- MAJOR
-
-
- Pylint
- F0003
- MAJOR
-
-
- Pylint
- F0004
- MAJOR
-
-
- Pylint
- F0010
- MAJOR
-
-
- Pylint
- F0202
- MAJOR
-
-
- Pylint
- F0220
- MAJOR
-
-
- Pylint
- F0321
- MAJOR
-
-
- Pylint
- F0401
- MAJOR
-
-
- Pylint
- I0001
- INFO
-
-
- Pylint
- I0010
- INFO
-
-
- Pylint
- I0011
- INFO
-
-
- Pylint
- I0012
- INFO
-
-
- Pylint
- I0013
- INFO
-
-
-
- Pylint
- R0201
- MINOR
-
-
- Pylint
- R0401
- MINOR
-
-
- Pylint
- R0801
- MINOR
-
-
- Pylint
- R0901
- MINOR
-
-
- Pylint
- R0902
- MINOR
-
-
- Pylint
- R0903
- MINOR
-
-
- Pylint
- R0904
- MINOR
-
-
- Pylint
- R0911
- MINOR
-
-
- Pylint
- R0912
- MINOR
-
-
- Pylint
- R0913
- MINOR
-
-
- Pylint
- R0914
- MINOR
-
-
- Pylint
- R0915
- MINOR
-
-
- Pylint
- R0921
- MINOR
-
-
- Pylint
- R0922
- MINOR
-
-
- Pylint
- R0923
- MINOR
-
-
- Pylint
- W0101
- MINOR
-
-
- Pylint
- W0102
- MINOR
-
-
- Pylint
- W0104
- MINOR
-
-
- Pylint
- W0105
- MINOR
-
-
- Pylint
- W0106
- MINOR
-
-
- Pylint
- W0107
- MINOR
-
-
- Pylint
- W0108
- MINOR
-
-
- Pylint
- W0109
- MINOR
-
-
- Pylint
- W0122
- MINOR
-
-
- Pylint
- W0141
- MINOR
-
-
- Pylint
- W0142
- MINOR
-
-
- Pylint
- W0150
- MINOR
-
-
- Pylint
- W0199
- MINOR
-
-
- Pylint
- W0201
- MINOR
-
-
- Pylint
- W0211
- MINOR
-
-
- Pylint
- W0212
- MINOR
-
-
- Pylint
- W0221
- MINOR
-
-
- Pylint
- W0222
- MINOR
-
-
- Pylint
- W0223
- MINOR
-
-
- Pylint
- W0231
- MINOR
-
-
- Pylint
- W0232
- MINOR
-
-
- Pylint
- W0233
- MINOR
-
-
- Pylint
- W0301
- MINOR
-
-
- Pylint
- W0311
- MINOR
-
-
- Pylint
- W0312
- MINOR
-
-
- Pylint
- W0331
- MINOR
-
-
- Pylint
- W0332
- MINOR
-
-
- Pylint
- W0333
- MINOR
-
-
- Pylint
- W0401
- MINOR
-
-
- Pylint
- W0402
- MINOR
-
-
- Pylint
- W0403
- MINOR
-
-
- Pylint
- W0404
- MINOR
-
-
- Pylint
- W0406
- MINOR
-
-
- Pylint
- W0410
- MINOR
-
-
- Pylint
- W0511
- MINOR
-
-
- Pylint
- W0601
- MINOR
-
-
- Pylint
- W0602
- MINOR
-
-
- Pylint
- W0603
- MINOR
-
-
- Pylint
- W0604
- MINOR
-
-
- Pylint
- W0611
- MINOR
-
-
- Pylint
- W0612
- MINOR
-
-
- Pylint
- W0613
- MINOR
-
-
- Pylint
- W0614
- MINOR
-
-
- Pylint
- W0621
- MINOR
-
-
- Pylint
- W0622
- MINOR
-
-
- Pylint
- W0631
- MINOR
-
-
- Pylint
- W0701
- MINOR
-
-
- Pylint
- W0702
- MINOR
-
-
- Pylint
- W0703
- MINOR
-
-
- Pylint
- W0704
- MINOR
-
-
- Pylint
- W0710
- MINOR
-
-
- Pylint
- W1001
- MINOR
-
-
- Pylint
- W1111
- MINOR
-
-
- Pylint
- W1201
- MINOR
-
-
- Pylint
- W1300
- MINOR
-
-
- Pylint
- W1301
- MINOR
-
-
-
-
-
- Pylint
- E1200
- MAJOR
-
-
- Pylint
- E1201
- MAJOR
-
-
- Pylint
- E1205
- MAJOR
-
-
- Pylint
- E1206
- MAJOR
-
-
diff --git a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/convert.py b/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/convert.py
deleted file mode 100755
index a62a9480b5..0000000000
--- a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/convert.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# Sonar Python Plugin
-# Copyright (C) 2011 Waleri Enns
-# Author(s) : Waleri Enns
-# waleri.enns@gmail.com
-
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 3 of the License, or (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
-
-
-#
-# Reads pylint --list-msgs from the stdin and writes XML to the stdout.
-# The latter is compatible with sonar rules.xml-schema.
-#
-
-import sys
-import re
-
-RULEID_PATTERN = ":[a-z _-]+ \(([A-Z][0-9]{4})\): ?\*?(.*?)\*?$"
-
-def parseNextRule(lines):
- ruleid, rulename = grabIdAndName(lines)
- ruledescr = grabDescr(lines)
- if ruleid:
- if not ruledescr:
- raise Exception("Invalid input")
- return Rule(ruleid, rulename, ruledescr)
- return None
-
-def grabIdAndName(lines):
- if not lines:
- return ""
- currline = lines.pop()
- ruleid = rulename = ""
- match = re.match(RULEID_PATTERN, currline)
- if match:
- ruleid, rulename = match.groups()
- return ruleid, rulename
-
-def grabDescr(lines):
- def partOfDescr(line):
- return line[:2] == " "
-
- descr = ""
- while lines:
- currline = lines.pop()
- if partOfDescr(currline):
- descr += " " + currline.strip()
- else:
- lines.append(currline)
- break
- return descr.strip()
-
-
-def header():
- return ('\n'
- '\n')
-
-
-def footer():
- return "\n"
-
-
-class Rule:
- def __init__(self, ruleid, rulename, ruledescr):
- self.ruleid = ruleid
- self.rulename = rulename
- self.ruledescr = ruledescr
-
- def __lt__(self, other):
- return self.ruleid < other.ruleid
-
- def toxml(self):
- rid = self.ruleid
- return ("\n"
- "%s\n"
- "\n"
- "%s\n"
- "\n"
- "\n"
- "\n"
- "\n"
- % (self.ruleid, self.rulename, self.ruleid, self.ruledescr))
-
-
-lines = sys.stdin.readlines()
-lines.reverse()
-
-# parse line oriented input format
-rules = []
-while(lines):
- rule = parseNextRule(lines)
- if rule:
- rules.append(rule)
-rules.sort()
-
-# generate rules-file as expected by sonar
-outstream = sys.stdout
-outstream.write(header())
-for rule in rules:
- outstream.write(rule.toxml())
-outstream.write(footer())
diff --git a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/generate_rules_file.sh b/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/generate_rules_file.sh
deleted file mode 100755
index 890051dec6..0000000000
--- a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/generate_rules_file.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-pylint --list-msgs | python convert.py > rules_generated.xml
diff --git a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/remediation-cost.csv b/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/remediation-cost.csv
deleted file mode 100644
index 7886c519da..0000000000
--- a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/remediation-cost.csv
+++ /dev/null
@@ -1,370 +0,0 @@
-C0102,1min
-C0103,1min
-C0111,5min
-C0112,5min
-C0113,1min
-C0121,20min
-C0122,1min
-C0123,15min
-C0200,20min
-C0201,20min
-C0202,10min
-C0203,10min
-C0204,20min
-C0205,15min
-C0301,1min
-C0302,30min
-C0303,1h
-C0304,10min
-C0305,1min
-C0321,5min
-C0322,1min
-C0323,1min
-C0324,1min
-C0325,5min
-C0326,1min
-C0327,15min
-C0328,1min
-C0330,5min
-C0401,1min
-C0402,1min
-C0403,1min
-C0410,5min
-C0411,5min
-C0412,5min
-C0413,5min
-C0414,5min
-C1001,20min
-C1801,20min
-E0001,5min
-E0011,5min
-E0012,5min
-E0100,30min
-E0101,5min
-E0102,15min
-E0103,15min
-E0104,5min
-E0105,10min
-E0106,15min
-E0107,3min
-E0108,5min
-E0109,10min
-E0110,5min
-E0111,10min
-E0112,5min
-E0113,5min
-E0114,5min
-E0116,15min
-E0115,15min
-E0117,5min
-E0119,5min
-E0202,15min
-E0203,15min
-E0211,10min
-E0213,5min
-E0221,20min
-E0222,30min
-E0235,10min
-E0236,10min
-E0237,10min
-E0238,20min
-E0239,20min
-E0240,20min
-E0241,20min
-E0301,10min
-E0302,20min
-E0303,20min
-E0401,10min
-E0402,20min
-E0501,5min
-E0502,5min
-E0503,10min
-E0601,15min
-E0602,20min
-E0603,20min
-E0604,3min
-E0611,10min
-E0632,20min
-E0633,20min
-E0701,30min
-E0702,20min
-E0703,5min
-E0704,10min
-E0710,15min
-E0711,5min
-E0712,20min
-E1001,10min
-E1002,10min
-E1003,10min
-E1004,10min
-E1101,10min
-E1102,3min
-E1103,10min
-E1111,20min
-E1120,5min
-E1121,5min
-E1122,3min
-E1123,3min
-E1124,5min
-E1125,5min
-E1126,15min
-E1127,15min
-E1128,15min
-E1129,15min
-E1130,15min
-E1131,15min
-E1132,15min
-E1133,15min
-E1134,15min
-E1135,15min
-E1136,15min
-E1137,15min
-E1138,15min
-E1139,15min
-E1140,5min
-E1200,10min
-E1201,10min
-E1205,10min
-E1206,10min
-E1300,3min
-E1301,3min
-E1302,5min
-E1303,10min
-E1304,10min
-E1305,5min
-E1306,5min
-E1307,5min
-E1310,10min
-E1507,5min
-E1601,5min
-E1602,10min
-E1603,10min
-E1604,5min
-E1605,5min
-E1606,10min
-E1607,5min
-E1608,3min
-E1609,10min
-E1610,10min
-E1700,15min
-E1701,5min
-F0001,15min
-F0002,15min
-F0003,15min
-F0004,15min
-F0010,15min
-F0202,15min
-F0220,15min
-F0321,15min
-F0401,15min
-I0001,15min
-I0010,15min
-I0011,15min
-I0012,15min
-I0013,15min
-I0020,15min
-I0021,15min
-I0022,15min
-I0023,5min
-I1101,15min
-R0123,20min
-R0124,1min
-R0201,20min
-R0202,15min
-R0203,15min
-R0205,1min
-R0401,2h
-R0801,15min
-R0901,3h
-R0902,2h
-R0903,1h
-R0904,2h
-R0911,20min
-R0912,15min
-R0913,30min
-R0914,20min
-R0915,15min
-R0916,20min
-R0921,20min
-R0922,45min
-R0923,20min
-R1701,20min
-R1702,30min
-R1703,10min
-R1704,1h
-R1705,20min
-R1706,20min
-R1707,1min
-R1708,5min
-R1709,20min
-R1710,20min
-R1711,1min
-R1712,1min
-R1713,1min
-R1714,1min
-R1715,1min
-R1716,1min
-R1717,15min
-R1718,15min
-R1719,1min
-R1720,1min
-W0101,15min
-W0102,15min
-W0104,15min
-W0105,15min
-W0106,15min
-W0107,1min
-W0108,5min
-W0109,10min
-W0110,15min
-W0111,20min
-W0120,20min
-W0121,5min
-W0122,30min
-W0123,30min
-W0124,30min
-W0125,30min
-W0141,15min
-W0142,15min
-W0143,1min
-W0150,20min
-W0199,5min
-W0201,5min
-W0211,10min
-W0212,1h
-W0221,15min
-W0222,20min
-W0223,1h
-W0231,20min
-W0232,20min
-W0233,2h
-W0234,15min
-W0235,1min
-W0301,1min
-W0311,1min
-W0312,1min
-W0331,1min
-W0332,1min
-W0333,1min
-W0401,1min
-W0402,1d
-W0403,15min
-W0404,1min
-W0406,15min
-W0410,10min
-W0511,1h
-W0512,15min
-W0601,15min
-W0602,15min
-W0603,1h
-W0604,1min
-W0611,1min
-W0612,5min
-W0613,15min
-W0614,1min
-W0621,15min
-W0622,5min
-W0623,20min
-W0631,15min
-W0632,15min
-W0633,15min
-W0640,20min
-W0641,1min
-W0642,5min
-W0701,15min
-W0702,15min
-W0703,20min
-W0704,15min
-W0705,10min
-W0706,1min
-W0710,15min
-W0711,15min
-W0712,15min
-W0715,5min
-W0716,5min
-W1001,20min
-W1111,15min
-W1113,5min
-W1201,5min
-W1202,5min
-W1203,1min
-W1300,5min
-W1301,5min
-W1302,5min
-W1303,5min
-W1304,5min
-W1305,5min
-W1306,5min
-W1307,5min
-W1308,1min
-W1401,5min
-W1402,15min
-W1403,1min
-W1501,15min
-W1502,15min
-W1503,15min
-W1505,15min
-W1506,15min
-W1507,15min
-W1508,5min
-W1509,15min
-W1601,15min
-W1602,5min
-W1603,5min
-W1604,5min
-W1605,5min
-W1606,5min
-W1607,5min
-W1608,5min
-W1609,5min
-W1610,5min
-W1611,5min
-W1612,5min
-W1613,5min
-W1614,5min
-W1615,5min
-W1616,5min
-W1617,5min
-W1618,5min
-W1619,5min
-W1620,5min
-W1621,5min
-W1622,5min
-W1623,5min
-W1624,5min
-W1625,5min
-W1626,5min
-W1627,5min
-W1628,5min
-W1629,5min
-W1630,5min
-W1632,5min
-W1633,5min
-W1634,5min
-W1635,5min
-W1636,5min
-W1637,5min
-W1638,5min
-W1639,5min
-W1640,5min
-W1641,5min
-W1642,5min
-W1643,5min
-W1644,5min
-W1645,5min
-W1646,5min
-W1647,5min
-W1649,5min
-W1650,5min
-W1651,5min
-W1652,5min
-W1653,5min
-W1654,5min
-W1655,5min
-W1656,5min
-W1657,5min
-W1658,5min
-W1659,5min
-W1660,5min
-W1661,5min
-W1662,5min
diff --git a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules.xml b/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules.xml
deleted file mode 100644
index 570de57723..0000000000
--- a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules.xml
+++ /dev/null
@@ -1,3507 +0,0 @@
-
-
-
- C0102
-
- C0102
-
- Pylint can be customized to help enforce coding
- guidelines that discourage or forbid use of certain names for
- variables, functions, etc. These names are specified with the
- bad-names option. This message is raised whenever a name is in the
- list of names defined with the bad-names option.
- ]]>
-
- MINOR
-
-
- C0103
-
- C0103
-
- This rule is deprecated, use {rule:python:S116}, {rule:python:S117}, {rule:python:S101},
- {rule:python:S100}, {rule:python:S1542}, {rule:python:S1578} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- C0111
-
- C0111
-
- This rule is deprecated, use {rule:python:S1720} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- C0112
-
- C0112
-
- This rule is deprecated, use {rule:python:S1720} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- C0113
-
- C0113
-
-
-
- MINOR
-
-
-
- C0121
-
- C0121
-
-
-
- MINOR
-
-
- C0122
-
- C0122
-
-
-
- MINOR
-
-
- C0123
-
- C0123
-
-
-
- MINOR
-
-
- C0200
-
- C0200
-
-
-
- MINOR
-
-
- C0201
-
- C0201
-
-
-
- MINOR
-
-
- C0202
-
- C0202
-
-
-
- MINOR
-
-
- C0203
-
- C0203
-
-
-
- MINOR
-
-
- C0204
-
- C0204
-
-
-
- MINOR
-
-
- C0205
-
- C0205
-
-
-
- MINOR
-
-
- C0301
-
- C0301
-
- This rule is deprecated, use {rule:python:LineLength} instead.]]>
-
- MINOR
- DEPRECATED
-
-
- C0302
-
- C0302
-
- This rule is deprecated, use {rule:python:S104} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- C0303
-
- C0303
-
- Added in Pylint 1.0.0.
- This rule is deprecated, use {rule:python:S1131} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- C0304
-
- C0304
-
- While Python interpreters typically do not require line
- end character(s) on the last line, other programs processing Python
- source files may do, and it is simply good practice to have it.
- Added in Pylint 1.0.0.
- This rule is deprecated, use {rule:python:S113} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- C0305
-
- C0305
-
-
-
- MINOR
-
-
- C0321
-
- C0321
-
- Used when more than one statement are found on the same line.
- This rule is deprecated, use {rule:python:OneStatementPerLine} instead.
]]>
-
- MINOR
- DEPRECATED
-
-
- C0322
-
- C0322
-
- = | < | > | = | \+= |-= | \*= | /= | %) is not preceded by a space.]]>
-
- MINOR
-
-
- C0323
-
- C0323
-
- = | < | > | = | \+= |-= | \*= | /= | %) is not followed by a space.]]>
-
- MINOR
-
-
- C0324
-
- C0324
-
-
-
- MINOR
-
-
- C0325
-
- C0325
-
- This rule was added in Pylint 1.1.0.
- This rule is deprecated, use {rule:python:S1110} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- C0326
-
- C0326
-
-
-
- MINOR
-
-
- C0327
-
- C0327
-
-
-
- MINOR
-
-
- C0328
-
- C0328
-
-
-
- MINOR
-
-
- C0330
-
- C0330
-
- Used when continued lines are badly indented.
- This rule was added in Pylint 1.2.1.
]]>
-
- MINOR
-
-
- C0401
-
- C0401
-
-
-
- MINOR
-
-
- C0402
-
- C0402
-
-
-
- MINOR
-
-
- C0403
-
- C0403
-
-
-
- MINOR
-
-
- C0410
-
- C0410
-
-
-
- MINOR
-
-
- C0411
-
- C0411
-
-
-
- MINOR
-
-
- C0412
-
- C0412
-
-
-
- MINOR
-
-
- C0413
-
- C0413
-
-
-
- MINOR
-
-
- C1001
-
- C1001
-
- = 3.0.
- This rule was added in Pylint 1.0.0.
- This rule is deprecated, use {rule:python:S1722} instead.
- ]]>
-
- MINOR
-
-
- C0414
-
- C0414
-
-
-
- MINOR
-
-
- C1801
-
- C1801
-
-
-
- MINOR
-
-
- E0001
-
- E0001
-
-
-
- MAJOR
-
-
- E0011
-
- E0011
-
- Note that options can be specified in the
- configuration file and can be overridden on the command line.
- ]]>
-
- MAJOR
-
-
- E0012
-
- E0012
-
- The option exists but its value is not valid. The options can be
- specified in the Pylint configuration file and can be overridden in
- the Pylint command line.
- ]]>
-
- MAJOR
-
-
- E0100
-
- E0100
-
- The __init__() method is required to return nothing. Python 2.7 and 3.x
- raise a TypeError when __init__() is called and executes a yield
- statement. Pylint reports this error without depending on the actual
- invocation.
- This rule is deprecated, use {rule:python:S2734} instead.
- ]]>
-
- MAJOR
- DEPRECATED
-
-
- E0101
-
- E0101
-
- The __init__() method is required to return
- nothing. Python raises a TypeError when __init__() is
- called and executes a return statement with a value other than
- None. Pylint reports this error without depending on the actual
- invocation.
- This rule is deprecated, use {rule:python:S2734} instead.
- ]]>
-
- MAJOR
- DEPRECATED
-
-
- E0102
-
- E0102
-
-
-
- MAJOR
-
-
- E0103
-
- E0103
-
- This rule is deprecated, use {rule:python:S1716} instead.
- ]]>
-
- MAJOR
- DEPRECATED
-
-
- E0104
-
- E0104
-
- This rule is deprecated, use {rule:python:S2711} instead.
- ]]>
-
- MAJOR
- DEPRECATED
-
-
- E0105
-
- E0105
-
- This rule is deprecated, use {rule:python:S2711} instead.
- ]]>
-
- MAJOR
- DEPRECATED
-
-
- E0106
-
- E0106
-
- = 3.3.
- This rule is deprecated, use {rule:python:S2712} instead.
- ]]>
-
- MAJOR
- DEPRECATED
-
-
- E0107
-
- E0107
-
- This rule is deprecated, use {rule:python:PreIncrementDecrement} instead.
- ]]>
-
- MAJOR
- DEPRECATED
-
-
- E0108
-
- E0108
-
- This rule was added in Pylint 0.28.0.]]>
-
- MINOR
-
-
- E0109
-
- E0109
-
-
-
- MINOR
-
-
- E0110
-
- E0110
-
-
-
- MINOR
-
-
- E0111
-
- E0111
-
- This rule was added in Pylint 1.2.0.]]>
-
- MINOR
-
-
- E0112
-
- E0112
-
-
-
- MAJOR
-
-
- E0113
-
- E0113
-
-
-
- MAJOR
-
-
- E0114
-
- E0114
-
-
-
- MAJOR
-
-
- E0115
-
- E0115
-
-
-
- MAJOR
-
-
- E0116
-
- E0116
-
-
-
- MINOR
-
-
- E0117
-
- E0117
-
-
-
- MAJOR
-
-
- E0119
-
- E0119
-
-
-
- MINOR
-
-
- E0202
-
- E0202
-
-
-
- MAJOR
-
-
- E0203
-
- E0203
-
-
-
- MAJOR
-
-
- E0211
-
- E0211
-
-
-
- MAJOR
-
-
- E0213
-
- E0213
-
-
-
- MAJOR
-
-
- E0221
-
- E0221
-
-
-
- MAJOR
-
-
- E0222
-
- E0222
-
-
-
- MAJOR
-
-
- E0235
-
- E0235
-
- This rule was added in Pylint 1.1.0.
- This rule is deprecated, use {rule:python:S2733} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- E0236
-
- E0236
-
- This rule was added in Pylint 1.2.0.]]>
-
- MINOR
-
-
- E0237
-
- E0237
-
-
-
- MINOR
-
-
- E0238
-
- E0238
-
- This rule was added in Pylint 1.2.0.]]>
-
- MINOR
-
-
- E0239
-
- E0239
-
-
-
- MINOR
-
-
- E0240
-
- E0240
-
-
-
- MINOR
-
-
- E0241
-
- E0241
-
-
-
- MINOR
-
-
- E0301
-
- E0301
-
-
-
- MINOR
-
-
- E0302
-
- E0302
-
-
-
- MINOR
-
-
- E0303
-
- E0303
-
-
-
- MINOR
-
-
- E0401
-
- E0401
-
-
-
- MINOR
-
-
- E0402
-
- E0402
-
-
-
- MINOR
-
-
- E0501
-
- E0501
-
-
-
- MAJOR
-
-
- E0502
-
- E0502
-
-
-
- MAJOR
-
-
- E0503
-
- E0503
-
-
-
- MAJOR
-
-
- E0601
-
- E0601
-
-
-
- MAJOR
-
-
- E0602
-
- E0602
-
-
-
- MAJOR
-
-
- E0603
-
- E0603
-
-
-
- MINOR
-
-
- E0604
-
- E0604
-
- This rule was added in Pylint 0.27.0.]]>
-
- MINOR
-
-
- E0611
-
- E0611
-
-
-
- MAJOR
-
-
- E0632
-
- E0632
-
-
-
- MINOR
-
-
- E0633
-
- E0633
-
-
-
- MINOR
-
-
- E0701
-
- E0701
-
-
-
- MAJOR
-
-
- E0702
-
- E0702
-
-
-
- MAJOR
-
-
- E0703
-
- E0703
-
-
-
- MINOR
-
-
- E0704
-
- E0704
-
-
-
- MAJOR
-
-
- E0710
-
- E0710
-
-
-
- MAJOR
-
-
- E0711
-
- E0711
-
-
-
- MAJOR
-
-
- E0712
-
- E0712
-
-
-
- MINOR
-
-
- E1001
-
- E1001
-
- = 3.0.]]>
-
- MAJOR
-
-
- E1002
-
- E1002
-
- = 3.0.]]>
-
- MAJOR
-
-
- E1003
-
- E1003
-
-
-
- MAJOR
-
-
- E1004
-
- E1004
-
- = 3.0.]]>
-
- MINOR
-
-
- E1101
-
- E1101
-
-
-
- MAJOR
-
-
- E1102
-
- E1102
-
-
-
- MAJOR
-
-
- E1103
-
- E1103
-
-
-
- MAJOR
-
-
- E1111
-
- E1111
-
-
-
- MAJOR
-
-
- E1120
-
- E1120
-
-
-
- MAJOR
-
-
- E1121
-
- E1121
-
-
-
- MAJOR
-
-
- E1122
-
- E1122
-
-
-
- MAJOR
-
-
- E1123
-
- E1123
-
-
-
- MAJOR
-
-
- E1124
-
- E1124
-
-
-
- MAJOR
-
-
- E1125
-
- E1125
-
-
-
- MAJOR
-
-
- E1126
-
- E1126
-
-
-
- MAJOR
-
-
- E1127
-
- E1127
-
-
-
- MAJOR
-
-
- E1128
-
- E1128
-
-
-
- MAJOR
-
-
- E1129
-
- E1129
-
-
-
- MAJOR
-
-
- E1130
-
- E1130
-
-
-
- MAJOR
-
-
- E1131
-
- E1131
-
-
-
- MAJOR
-
-
- E1132
-
- E1132
-
-
-
- MAJOR
-
-
- E1133
-
- E1133
-
-
-
- MAJOR
-
-
- E1134
-
- E1134
-
-
-
- MAJOR
-
-
- E1135
-
- E1135
-
-
-
- MAJOR
-
-
- E1136
-
- E1136
-
-
-
- MAJOR
-
-
- E1137
-
- E1137
-
-
-
- MAJOR
-
-
- E1138
-
- E1138
-
-
-
- MAJOR
-
-
- E1139
-
- E1139
-
-
-
- MAJOR
-
-
- E1140
-
- E1140
-
-
-
- MAJOR
-
-
- E1200
-
- E1200
-
-
-
- MAJOR
-
-
- E1201
-
- E1201
-
-
-
- MAJOR
-
-
- E1205
-
- E1205
-
-
-
- MAJOR
-
-
- E1206
-
- E1206
-
-
-
- MAJOR
-
-
- E1300
-
- E1300
-
-
-
- MAJOR
-
-
- E1301
-
- E1301
-
-
-
- MAJOR
-
-
- E1302
-
- E1302
-
-
-
- MAJOR
-
-
- E1303
-
- E1303
-
-
-
- MAJOR
-
-
- E1304
-
- E1304
-
-
-
- MAJOR
-
-
- E1305
-
- E1305
-
-
-
- MAJOR
-
-
- E1306
-
- E1306
-
-
-
- MAJOR
-
-
- E1307
-
- E1307
-
-
-
- MINOR
-
-
- E1310
-
- E1310
-
- This rule was added in Pylint 0.28.0.]]>
-
- MINOR
-
-
- E1507
-
- E1507
-
-
-
- MINOR
-
-
- E1601
-
- E1601
-
-
-
- MAJOR
-
-
- E1602
-
- E1602
-
-
-
- MAJOR
-
-
- E1603
-
- E1603
-
-
-
- MAJOR
-
-
- E1604
-
- E1604
-
-
-
- MAJOR
-
-
- E1605
-
- E1605
-
-
-
- MAJOR
-
-
- E1606
-
- E1606
-
- = 3.0.]]>
-
- MAJOR
-
-
- E1607
- operator]]>
- E1607
-
- " operator is used instead of "!=". This is removed in Python 3. This message can't be emitted when using Python >= 3.0.]]>
-
- MAJOR
-
-
- E1608
-
- E1608
-
- = 3.0.]]>
-
- MAJOR
-
-
- E1609
-
- E1609
-
- = 3.0.]]>
-
- MAJOR
-
-
- E1610
-
- E1610
-
- = 3.0.]]>
-
- MAJOR
-
-
- E1700
-
- E1700
-
-
-
- MAJOR
-
-
- E1701
-
- E1701
-
-
-
- MINOR
-
-
- F0001
-
- F0001
-
-
-
- MAJOR
-
-
- F0002
-
- F0002
-
-
-
- MAJOR
-
-
- F0003
-
- F0003
-
-
-
- MAJOR
-
-
- F0004
-
- F0004
-
-
-
- MAJOR
-
-
- F0010
-
- F0010
-
-
-
- MAJOR
-
-
- F0202
-
- F0202
-
-
-
- MAJOR
-
-
- F0220
-
- F0220
-
-
-
- MAJOR
-
-
- F0321
-
- F0321
-
-
-
- MAJOR
-
-
- F0401
-
- F0401
-
-
-
- MAJOR
-
-
- I0001
-
- I0001
-
-
-
- INFO
-
-
- I0010
-
- I0010
-
-
-
- INFO
-
-
- I0011
-
- I0011
-
-
-
- INFO
-
-
- I0012
-
- I0012
-
-
-
- INFO
-
-
- I0013
-
- I0013
-
-
-
- INFO
-
-
- I0020
-
- I0020
-
-
-
- INFO
-
-
- I0021
-
- I0021
-
-
-
- INFO
-
-
- I0022
-
- I0022
-
- = 0.26]]>
-
- INFO
-
-
- I0023
-
- I0023
-
-
-
- INFO
-
-
- I1101
-
- I1101
-
-
-
- INFO
-
-
- R0123
-
- R0123
-
-
-
- MINOR
-
-
- R0124
-
- R0124
-
-
-
- MINOR
-
-
- R0201
-
- R0201
-
- This rule is deprecated, use {rule:python:S2325} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- R0202
-
- R0202
-
-
-
- MINOR
-
-
- R0203
-
- R0203
-
-
-
- MINOR
-
-
- R0205
-
- R0205
-
-
-
- MINOR
-
-
- R0401
-
- R0401
-
- While cyclic imports terminate and execute without
- surprises in most cases, the circular dependency often indicates a
- design issue in the code base.
- ]]>
-
- MINOR
-
-
- R0801
-
- R0801
-
- This rule is deprecated, use {rule:common-py:DuplicatedBlocks} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- R0901
-
- R0901
-
-
-
- MINOR
-
-
- R0902
-
- R0902
-
-
-
- MINOR
-
-
- R0903
-
- R0903
-
-
-
- MINOR
-
-
- R0904
-
- R0904
-
-
-
- MINOR
-
-
- R0911
-
- R0911
-
- This rule is deprecated, use {rule:python:S1142} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- R0912
-
- R0912
-
- This rule is deprecated, use {rule:python:FunctionComplexity} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- R0913
-
- R0913
-
- This rule is deprecated, use {rule:python:S107} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- R0914
-
- R0914
-
-
-
- MINOR
-
-
- R0915
-
- R0915
-
-
-
- MINOR
-
-
- R0916
-
- R0916
-
-
-
- MINOR
-
-
- R0921
-
- R0921
-
-
-
- MINOR
-
-
- R0922
-
- R0922
-
-
-
- MINOR
-
-
- R0923
-
- R0923
-
-
-
- MINOR
-
-
- R1701
-
- R1701
-
-
-
- MINOR
-
-
- R1702
-
- R1702
-
-
-
- MINOR
-
-
- R1703
-
- R1703
-
-
-
- MINOR
-
-
- R1704
-
- R1704
-
-
-
- MINOR
-
-
- R1705
-
- R1705
-
-
-
- MINOR
-
-
- R1706
-
- R1706
-
-
-
- MINOR
-
-
- R1707
-
- R1707
-
-
-
- MINOR
-
-
- R1708
-
- R1708
-
-
-
- MINOR
-
-
- R1709
-
- R1709
-
-
-
- MINOR
-
-
- R1710
-
- R1710
-
-
-
- MINOR
-
-
- R1711
-
- R1711
-
-
-
- MINOR
-
-
- R1712
-
- R1712
-
-
-
- MINOR
-
-
- R1713
-
- R1713
-
-
-
- MINOR
-
-
- R1714
-
- R1714
-
-
-
- MINOR
-
-
- R1715
-
- R1715
-
-
-
- MINOR
-
-
- R1716
-
- R1716
-
-
-
- MINOR
-
-
- R1717
-
- R1717
-
-
-
- MINOR
-
-
- R1718
-
- R1718
-
-
-
- MINOR
-
-
- R1719
-
- R1719
-
-
-
- MINOR
-
-
- R1720
-
- R1720
-
-
-
- MINOR
-
-
- W0101
-
- W0101
-
- This rule is deprecated, use {rule:python:S1763} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- W0102
-
- W0102
-
-
-
- MINOR
-
-
- W0104
-
- W0104
-
-
-
- MINOR
-
-
- W0105
-
- W0105
-
-
-
- MINOR
-
-
- W0106
-
- W0106
-
-
-
- MINOR
-
-
- W0107
-
- W0107
-
- This rule is deprecated, use {rule:python:S2772} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- W0108
-
- W0108
-
-
-
- MINOR
-
-
- W0109
-
- W0109
-
-
-
- MINOR
-
-
- W0110
-
- W0110
-
- = 3.0.
- This rule was added in Pylint 0.27.0.
]]>
-
- MINOR
-
-
- W0111
-
- W0111
-
-
-
- MINOR
-
-
- W0120
-
- W0120
-
- This rule was added in Pylint 0.28.0.]]>
-
- MINOR
-
-
- W0121
-
- W0121
-
- = 3.0.
- This rule was added in Pylint 1.0.0.
]]>
-
- MINOR
-
-
- W0122
-
- W0122
-
- This rule is deprecated, use {rule:python:ExecStatementUsage} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- W0123
-
- W0123
-
- This rule was added in Pylint 1.2.0.]]>
-
- MINOR
-
-
- W0124
-
- W0124
-
-
-
- MINOR
-
-
- W0125
-
- W0125
-
-
-
- MINOR
-
-
- W0141
-
- W0141
-
-
-
- MINOR
-
-
- W0142
-
- W0142
-
-
-
- MINOR
-
-
- W0143
-
- W0143
-
-
-
- MINOR
-
-
- W0150
-
- W0150
-
-
-
- MINOR
-
-
- W0199
-
- W0199
-
-
-
- MINOR
-
-
- W0201
-
- W0201
-
-
-
- MINOR
-
-
- W0211
-
- W0211
-
-
-
- MINOR
-
-
- W0212
-
- W0212
-
-
-
- MINOR
-
-
- W0221
-
- W0221
-
-
-
- MINOR
-
-
- W0222
-
- W0222
-
-
-
- MINOR
-
-
- W0223
-
- W0223
-
-
-
- MINOR
-
-
- W0231
-
- W0231
-
-
-
- MINOR
-
-
- W0232
-
- W0232
-
-
-
- MINOR
-
-
- W0233
-
- W0233
-
-
-
- MINOR
-
-
- W0234
-
- W0234
-
- This rule was added in Pylint 1.1.0.]]>
-
- MINOR
-
-
- W0235
-
- W0235
-
-
-
- MINOR
-
-
- W0301
-
- W0301
-
-
-
- MINOR
-
-
- W0311
-
- W0311
-
-
-
- MINOR
-
-
- W0312
-
- W0312
-
- As indentation is part of Python's syntax,
- inconsistencies in its usage are usually considered a
- major issue.
- ]]>
-
- MAJOR
-
-
- W0331
- operator]]>
- W0331
-
- " operator is used instead of "!=".
- This rule is deprecated, use {rule:python:InequalityUsage} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- W0332
-
- W0332
-
- = 3.0.]]>
-
- MINOR
-
-
- W0333
-
- W0333
-
- This rule is deprecated, use {rule:python:BackticksUsage} instead.
- ]]>
-
- MINOR
- DEPRECATED
-
-
- W0401
-
- W0401
-
-
-
- MINOR
-
-
- W0402
-
- W0402
-
-
-
- MINOR
-
-
- W0403
-
- W0403
-
- = 3.0.]]>
-
- MINOR
-
-
- W0404
-
- W0404
-
-
-
- MINOR
-
-
- W0406
-
- W0406
-
-
-
- MINOR
-
-
- W0410
-
- W0410
-
-
-
- MINOR
-
-
- W0511
-
- W0511
-
-
-
- MINOR
-
-
- W0512
-
- W0512
-
- = 3.0.
- This rule was added in Pylint 1.0.0.
]]>
-
- MINOR
-
-
- W0601
-
- W0601
-
-
-
- MINOR
-
-
- W0602
-
- W0602
-
-
-
- MINOR
-
-
- W0603
-
- W0603
-
-
-
- MINOR
-
-
- W0604
-
- W0604
-
-
-
- MINOR
-
-
- W0611
-
- W0611
-
-
-
- MINOR
-
-
- W0612
-
- W0612
-
-
-
- MINOR
-
-
- W0613
-
- W0613
-
-
-
- MINOR
-
-
- W0614
-
- W0614
-
-
-
- MINOR
-
-
- W0621
-
- W0621
-
-
-
- MINOR
-
-
- W0622
-
- W0622
-
-
-
- MINOR
-
-
- W0623
-
- W0623
-
-
-
- MINOR
-
-
- W0631
-
- W0631
-
-
-
- MINOR
-
-
- W0632
-
- W0632
-
- This rule was added in Pylint 1.1.0.]]>
-
- MINOR
-
-
- W0633
-
- W0633
-
- This rule was added in Pylint 1.1.0.]]>
-
- MINOR
-
-
- W0640
-
- W0640
-
-
-
- MINOR
-
-
- W0641
-
- W0641
-
-
-
- MINOR
-
-
- W0642
-
- W0642
-
-
-
- MINOR
-
-
- W0701
-
- W0701
-
-
-
- MINOR
-
-
- W0702
-
- W0702
-
- Catching exceptions should be as precise as
- possible. The type of exceptions that can be raised should be known in
- advance. Using catch-all-constructs hides potential
- errors (including syntax ones), defeats the purpose of
- knowing the type of error that occurred, and prohibits the use of
- tailored responses.
- ]]>
-
- MINOR
-
-
- W0703
-
- W0703
-
- Catching exceptions should be as precise as possible. The type of
- exceptions that can be raised should be known in advance. Using a
- catch-all Exception instance defeats the purpose of knowing the type
- of error that occur-ed, and prohibits the use of tailored responses.
- ]]>
-
- MINOR
-
-
- W0704
-
- W0704
-
-
-
- MINOR
-
-
- W0705
-
- W0705
-
-
-
- MINOR
-
-
- W0706
-
- W0706
-
-
-
- MINOR
-
-
- W0710
-
- W0710
-
- = 3.0.]]>
-
- MINOR
-
-
- W0711
-
- W0711
-
-
-
- MINOR
-
-
- W0712
-
- W0712
-
- = 3.0.
- This rule was added in Pylint 1.0.0.
]]>
-
- MINOR
-
-
- W0715
-
- W0715
-
-
-
- MINOR
-
-
- W0716
-
- W0716
-
-
-
- MINOR
-
-
- W1001
-
- W1001
-
- = 3.0.]]>
-
- MINOR
-
-
- W1111
-
- W1111
-
-
-
- MINOR
-
-
- W1113
-
- W1113
-
-
-
- MINOR
-
-
- W1201
-
- W1201
-
- (format_string % (format_args...))". Such
- calls should leave string interpolation to the logging method itself
- and be written "logging.(format_string,
- format_args...)" so that the program may avoid incurring the cost of
- the interpolation in those cases in which no message will be
- logged. For more, see http://www.python.org/dev/peps/pep-0282/.]]>
-
- MINOR
-
-
- W1202
-
- W1202
-
- (format_string.format(format_args...))". Such calls should use % formatting instead, but leave interpolation to the logging function by passing the parameters as arguments.]]>
-
- MINOR
-
-
- W1203
-
- W1203
-
-
-
- MINOR
-
-
- W1300
-
- W1300
-
-
-
- MINOR
-
-
- W1301
-
- W1301
-
-
-
- MINOR
-
-
- W1302
-
- W1302
-
-
-
- MINOR
-
-
- W1303
-
- W1303
-
-
-
- MINOR
-
-
- W1304
-
- W1304
-
-
-
- MINOR
-
-
- W1305
-
- W1305
-
-
-
- MINOR
-
-
- W1306
-
- W1306
-
-
-
- MINOR
-
-
- W1307
-
- W1307
-
-
-
- MINOR
-
-
- W1308
-
- W1308
-
-
-
- MINOR
-
-
- W1401
-
- W1401
-
- This rule was added in Pylint 0.26.0.
- This rule is deprecated, use {rule:python:S1717} instead.
]]>
-
- MINOR
- DEPRECATED
-
-
- W1402
-
- W1402
-
- This rule was added in Pylint 0.26.0.]]>
-
- MINOR
-
-
- W1403
-
- W1403
-
-
-
- MINOR
-
-
- W1501
-
- W1501
-
-
-
- MINOR
-
-
- W1502
-
- W1502
-
- = 3.5.]]>
-
- MINOR
-
-
- W1503
-
- W1503
-
-
-
- MINOR
-
-
- W1505
-
- W1505
-
-
-
- MINOR
-
-
- W1506
-
- W1506
-
-
-
- MINOR
-
-
- W1507
-
- W1507
-
-
-
- MINOR
-
-
- W1508
-
- W1508
-
-
-
- MINOR
-
-
- W1509
-
- W1509
-
-
-
- MINOR
-
-
- W1601
-
- W1601
-
-
-
- MINOR
-
-
- W1602
-
- W1602
-
-
-
- MINOR
-
-
- W1603
-
- W1603
-
-
-
- MINOR
-
-
- W1604
-
- W1604
-
-
-
- MINOR
-
-
- W1605
-
- W1605
-
-
-
- MINOR
-
-
- W1606
-
- W1606
-
-
-
- MINOR
-
-
- W1607
-
- W1607
-
-
-
- MINOR
-
-
- W1608
-
- W1608
-
-
-
- MINOR
-
-
- W1609
-
- W1609
-
-
-
- MINOR
-
-
- W1610
-
- W1610
-
-
-
- MINOR
-
-
- W1611
-
- W1611
-
-
-
- MINOR
-
-
- W1612
-
- W1612
-
-
-
- MINOR
-
-
- W1613
-
- W1613
-
-
-
- MINOR
-
-
- W1614
-
- W1614
-
-
-
- MINOR
-
-
- W1615
-
- W1615
-
-
-
- MINOR
-
-
- W1616
-
- W1616
-
-
-
- MINOR
-
-
- W1617
-
- W1617
-
-
-
- MINOR
-
-
- W1618
-
- W1618
-
-
-
- MINOR
-
-
- W1619
-
- W1619
-
-
-
- MINOR
-
-
- W1620
-
- W1620
-
-
-
- MINOR
-
-
- W1621
-
- W1621
-
-
-
- MINOR
-
-
- W1622
-
- W1622
-
-
-
- MINOR
-
-
- W1623
-
- W1623
-
-
-
- MINOR
-
-
- W1624
-
- W1624
-
-
-
- MINOR
-
-
- W1625
-
- W1625
-
-
-
- MINOR
-
-
- W1626
-
- W1626
-
-
-
- MINOR
-
-
- W1627
-
- W1627
-
-
-
- MINOR
-
-
- W1628
-
- W1628
-
-
-
- MINOR
-
-
- W1629
-
- W1629
-
-
-
- MINOR
-
-
- W1630
-
- W1630
-
-
-
- MINOR
-
-
- W1632
-
- W1632
-
-
-
- MINOR
-
-
- W1633
-
- W1633
-
-
-
- MINOR
-
-
- W1634
-
- W1634
-
-
-
- MINOR
-
-
- W1635
-
- W1635
-
-
-
- MINOR
-
-
- W1636
-
- W1636
-
-
-
- MINOR
-
-
- W1637
-
- W1637
-
-
-
- MINOR
-
-
- W1638
-
- W1638
-
-
-
- MINOR
-
-
- W1639
-
- W1639
-
-
-
- MINOR
-
-
- W1640
-
- W1640
-
-
-
- MINOR
-
-
- W1641
-
- W1641
-
-
-
- MINOR
-
-
- W1642
-
- W1642
-
-
-
- MINOR
-
-
- W1643
-
- W1643
-
-
-
- MINOR
-
-
- W1644
-
- W1644
-
-
-
- MINOR
-
-
- W1645
-
- W1645
-
-
-
- MINOR
-
-
- W1646
-
- W1646
-
-
-
- MINOR
-
-
- W1647
-
- W1647
-
-
-
- MINOR
-
-
- W1649
-
- W1649
-
-
-
- MINOR
-
-
- W1650
-
- W1650
-
-
-
- MINOR
-
-
- W1651
-
- W1651
-
-
-
- MINOR
-
-
- W1652
-
- W1652
-
-
-
- MINOR
-
-
- W1653
-
- W1653
-
-
-
- MINOR
-
-
- W1654
-
- W1654
-
-
-
- MINOR
-
-
- W1655
-
- W1655
-
-
-
- MINOR
-
-
- W1656
-
- W1656
-
-
-
- MINOR
-
-
- W1657
-
- W1657
-
-
-
- MINOR
-
-
- W1658
-
- W1658
-
-
-
- MINOR
-
-
- W1659
-
- W1659
-
-
-
- MAJOR
-
-
- W1660
-
- W1660
-
-
-
- MINOR
-
-
- W1661
-
- W1661
-
-
-
- MINOR
-
-
- W1662
-
- W1662
-
-
-
- MINOR
-
-
diff --git a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules_generated.xml b/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules_generated.xml
deleted file mode 100644
index 73fefc5593..0000000000
--- a/sonar-python-plugin/src/main/resources/org/sonar/plugins/python/pylint/rules_generated.xml
+++ /dev/null
@@ -1,2563 +0,0 @@
-
-
-
-C0102
-
-C0102
-
-
-
-
-
-C0103
-
-C0103
-
-
-
-
-
-C0111
-
-C0111
-
-
-
-
-
-C0112
-
-C0112
-
-
-
-
-
-C0113
-
-C0113
-
-
-
-
-
-C0121
-
-C0121
-
-
-
-
-
-C0122
-
-C0122
-
-
-
-
-
-C0123
-
-C0123
-
-
-
-
-
-C0200
-
-C0200
-
-
-
-
-
-C0201
-
-C0201
-
-
-
-
-
-C0202
-
-C0202
-
-
-
-
-
-C0203
-
-C0203
-
-
-
-
-
-C0204
-
-C0204
-
-
-
-
-
-C0205
-
-C0205
-
-
-
-
-
-C0301
-
-C0301
-
-
-
-
-
-C0302
-
-C0302
-
-
-
-
-
-C0303
-
-C0303
-
-
-
-
-
-C0304
-
-C0304
-
-
-
-
-
-C0305
-
-C0305
-
-
-
-
-
-C0321
-
-C0321
-
-
-
-
-
-C0325
-
-C0325
-
-
-
-
-
-C0326
-
-C0326
-
-
-
-
-
-C0327
-
-C0327
-
-
-
-
-
-C0328
-
-C0328
-
-
-
-
-
-C0330
-
-C0330
-
-
-
-
-
-C0401
-
-C0401
-
-
-
-
-
-C0402
-
-C0402
-
-
-
-
-
-C0403
-
-C0403
-
-
-
-
-
-C0410
-
-C0410
-
-
-
-
-
-C0411
-
-C0411
-
-
-
-
-
-C0412
-
-C0412
-
-
-
-
-
-C0413
-
-C0413
-
-
-
-
-
-C0414
-
-C0414
-
-
-
-
-
-C1801
-
-C1801
-
-
-
-
-
-E0001
-
-E0001
-
-
-
-
-
-E0011
-
-E0011
-
-
-
-
-
-E0012
-
-E0012
-
-
-
-
-
-E0100
-
-E0100
-
-
-
-
-
-E0101
-
-E0101
-
-
-
-
-
-E0102
-
-E0102
-
-
-
-
-
-E0103
-
-E0103
-
-
-
-
-
-E0104
-
-E0104
-
-
-
-
-
-E0105
-
-E0105
-
-
-
-
-
-E0107
-
-E0107
-
-
-
-
-
-E0108
-
-E0108
-
-
-
-
-
-E0110
-
-E0110
-
-
-
-
-
-E0111
-
-E0111
-
-
-
-
-
-E0112
-
-E0112
-
-
-
-
-
-E0113
-
-E0113
-
-
-
-
-
-E0114
-
-E0114
-
-
-
-
-
-E0115
-
-E0115
-
-
-
-
-
-E0116
-
-E0116
-
-
-
-
-
-E0117
-
-E0117
-
-
-
-
-
-E0119
-
-E0119
-
-
-
-
-
-E0202
-
-E0202
-
-
-
-
-
-E0203
-
-E0203
-
-
-
-
-
-E0211
-
-E0211
-
-
-
-
-
-E0213
-
-E0213
-
-
-
-
-
-E0236
-
-E0236
-
-
-
-
-
-E0237
-
-E0237
-
-
-
-
-
-E0238
-
-E0238
-
-
-
-
-
-E0239
-
-E0239
-
-
-
-
-
-E0240
-
-E0240
-
-
-
-
-
-E0241
-
-E0241
-
-
-
-
-
-E0301
-
-E0301
-
-
-
-
-
-E0302
-
-E0302
-
-
-
-
-
-E0303
-
-E0303
-
-
-
-
-
-E0401
-
-E0401
-
-
-
-
-
-E0402
-
-E0402
-
-
-
-
-
-E0601
-
-E0601
-
-
-
-
-
-E0602
-
-E0602
-
-
-
-
-
-E0603
-
-E0603
-
-
-
-
-
-E0604
-
-E0604
-
-
-
-
-
-E0611
-
-E0611
-
-
-
-
-
-E0633
-
-E0633
-
-
-
-
-
-E0701
-
-E0701
-
-
-
-
-
-E0702
-
-E0702
-
-
-
-
-
-E0703
-
-E0703
-
-
-
-
-
-E0704
-
-E0704
-
-
-
-
-
-E0710
-
-E0710
-
-
-
-
-
-E0711
-
-E0711
-
-
-
-
-
-E0712
-
-E0712
-
-
-
-
-
-E1003
-
-E1003
-
-
-
-
-
-E1101
-
-E1101
-
-
-
-
-
-E1102
-
-E1102
-
-
-
-
-
-E1111
-
-E1111
-
-
-
-
-
-E1120
-
-E1120
-
-
-
-
-
-E1121
-
-E1121
-
-
-
-
-
-E1123
-
-E1123
-
-
-
-
-
-E1124
-
-E1124
-
-
-
-
-
-E1125
-
-E1125
-
-
-
-
-
-E1126
-
-E1126
-
-
-
-
-
-E1127
-
-E1127
-
-
-
-
-
-E1128
-
-E1128
-
-
-
-
-
-E1129
-
-E1129
-
-
-
-
-
-E1130
-
-E1130
-
-
-
-
-
-E1131
-
-E1131
-
-
-
-
-
-E1132
-
-E1132
-
-
-
-
-
-E1133
-
-E1133
-
-
-
-
-
-E1134
-
-E1134
-
-
-
-
-
-E1135
-
-E1135
-
-
-
-
-
-E1136
-
-E1136
-
-
-
-
-
-E1137
-
-E1137
-
-
-
-
-
-E1138
-
-E1138
-
-
-
-
-
-E1139
-
-E1139
-
-
-
-
-
-E1140
-
-E1140
-
-
-
-
-
-E1200
-
-E1200
-
-
-
-
-
-E1201
-
-E1201
-
-
-
-
-
-E1205
-
-E1205
-
-
-
-
-
-E1206
-
-E1206
-
-
-
-
-
-E1300
-
-E1300
-
-
-
-
-
-E1301
-
-E1301
-
-
-
-
-
-E1302
-
-E1302
-
-
-
-
-
-E1303
-
-E1303
-
-
-
-
-
-E1304
-
-E1304
-
-
-
-
-
-E1305
-
-E1305
-
-
-
-
-
-E1306
-
-E1306
-
-
-
-
-
-E1307
-
-E1307
-
-
-
-
-
-E1310
-
-E1310
-
-
-
-
-
-E1507
-
-E1507
-
-
-
-
-
-E1601
-
-E1601
-
-
-
-
-
-E1602
-
-E1602
-
-
-
-
-
-E1603
-
-E1603
-
-
-
-
-
-E1604
-
-E1604
-
-
-
-
-
-E1605
-
-E1605
-
-
-
-
-
-E1700
-
-E1700
-
-
-
-
-
-E1701
-
-E1701
-
-
-
-
-
-F0001
-
-F0001
-
-
-
-
-
-F0002
-
-F0002
-
-
-
-
-
-F0010
-
-F0010
-
-
-
-
-
-F0202
-
-F0202
-
-
-
-
-
-I0001
-
-I0001
-
-
-
-
-
-I0010
-
-I0010
-
-
-
-
-
-I0011
-
-I0011
-
-
-
-
-
-I0013
-
-I0013
-
-
-
-
-
-I0020
-
-I0020
-
-
-
-
-
-I0021
-
-I0021
-
-
-
-
-
-I0022
-
-I0022
-
-= 0.26]]>
-
-
-
-I0023
-
-I0023
-
-
-
-
-
-I1101
-
-I1101
-
-
-
-
-
-R0123
-
-R0123
-
-
-
-
-
-R0124
-
-R0124
-
-
-
-
-
-R0201
-
-R0201
-
-
-
-
-
-R0202
-
-R0202
-
-
-
-
-
-R0203
-
-R0203
-
-
-
-
-
-R0205
-
-R0205
-
-
-
-
-
-R0401
-
-R0401
-
-
-
-
-
-R0801
-
-R0801
-
-
-
-
-
-R0901
-
-R0901
-
-
-
-
-
-R0902
-
-R0902
-
-
-
-
-
-R0903
-
-R0903
-
-
-
-
-
-R0904
-
-R0904
-
-
-
-
-
-R0911
-
-R0911
-
-
-
-
-
-R0912
-
-R0912
-
-
-
-
-
-R0913
-
-R0913
-
-
-
-
-
-R0914
-
-R0914
-
-
-
-
-
-R0915
-
-R0915
-
-
-
-
-
-R0916
-
-R0916
-
-
-
-
-
-R1701
-
-R1701
-
-
-
-
-
-R1702
-
-R1702
-
-
-
-
-
-R1703
-
-R1703
-
-
-
-
-
-R1704
-
-R1704
-
-
-
-
-
-R1705
-
-R1705
-
-
-
-
-
-R1706
-
-R1706
-
-
-
-
-
-R1707
-
-R1707
-
-
-
-
-
-R1708
-
-R1708
-
-
-
-
-
-R1709
-
-R1709
-
-
-
-
-
-R1710
-
-R1710
-
-
-
-
-
-R1711
-
-R1711
-
-
-
-
-
-R1712
-
-R1712
-
-
-
-
-
-R1713
-
-R1713
-
-
-
-
-
-R1714
-
-R1714
-
-
-
-
-
-R1715
-
-R1715
-
-
-
-
-
-R1716
-
-R1716
-
-
-
-
-
-R1717
-
-R1717
-
-
-
-
-
-R1718
-
-R1718
-
-
-
-
-
-R1719
-
-R1719
-
-
-
-
-
-R1720
-
-R1720
-
-
-
-
-
-W0101
-
-W0101
-
-
-
-
-
-W0102
-
-W0102
-
-
-
-
-
-W0104
-
-W0104
-
-
-
-
-
-W0105
-
-W0105
-
-
-
-
-
-W0106
-
-W0106
-
-
-
-
-
-W0107
-
-W0107
-
-
-
-
-
-W0108
-
-W0108
-
-
-
-
-
-W0109
-
-W0109
-
-
-
-
-
-W0111
-
-W0111
-
-
-
-
-
-W0120
-
-W0120
-
-
-
-
-
-W0122
-
-W0122
-
-
-
-
-
-W0123
-
-W0123
-
-
-
-
-
-W0124
-
-W0124
-
-
-
-
-
-W0125
-
-W0125
-
-
-
-
-
-W0143
-
-W0143
-
-
-
-
-
-W0150
-
-W0150
-
-
-
-
-
-W0199
-
-W0199
-
-
-
-
-
-W0201
-
-W0201
-
-
-
-
-
-W0211
-
-W0211
-
-
-
-
-
-W0212
-
-W0212
-
-
-
-
-
-W0221
-
-W0221
-
-
-
-
-
-W0222
-
-W0222
-
-
-
-
-
-W0223
-
-W0223
-
-
-
-
-
-W0231
-
-W0231
-
-
-
-
-
-W0232
-
-W0232
-
-
-
-
-
-W0233
-
-W0233
-
-
-
-
-
-W0235
-
-W0235
-
-
-
-
-
-W0301
-
-W0301
-
-
-
-
-
-W0311
-
-W0311
-
-
-
-
-
-W0312
-
-W0312
-
-
-
-
-
-W0401
-
-W0401
-
-
-
-
-
-W0402
-
-W0402
-
-
-
-
-
-W0404
-
-W0404
-
-
-
-
-
-W0406
-
-W0406
-
-
-
-
-
-W0410
-
-W0410
-
-
-
-
-
-W0511
-
-W0511
-
-
-
-
-
-W0601
-
-W0601
-
-
-
-
-
-W0602
-
-W0602
-
-
-
-
-
-W0603
-
-W0603
-
-
-
-
-
-W0604
-
-W0604
-
-
-
-
-
-W0611
-
-W0611
-
-
-
-
-
-W0612
-
-W0612
-
-
-
-
-
-W0613
-
-W0613
-
-
-
-
-
-W0614
-
-W0614
-
-
-
-
-
-W0621
-
-W0621
-
-
-
-
-
-W0622
-
-W0622
-
-
-
-
-
-W0623
-
-W0623
-
-
-
-
-
-W0631
-
-W0631
-
-
-
-
-
-W0632
-
-W0632
-
-
-
-
-
-W0640
-
-W0640
-
-
-
-
-
-W0641
-
-W0641
-
-
-
-
-
-W0642
-
-W0642
-
-
-
-
-
-W0702
-
-W0702
-
-
-
-
-
-W0703
-
-W0703
-
-
-
-
-
-W0705
-
-W0705
-
-
-
-
-
-W0706
-
-W0706
-
-
-
-
-
-W0711
-
-W0711
-
-
-
-
-
-W0715
-
-W0715
-
-
-
-
-
-W0716
-
-W0716
-
-
-
-
-
-W1113
-
-W1113
-
-
-
-
-
-W1201
-
-W1201
-
-(format_string % (format_args...))". Such calls should leave string interpolation to the logging method itself and be written "logging.(format_string, format_args...)" so that the program may avoid incurring the cost of the interpolation in those cases in which no message will be logged. For more, see http://www.python.org/dev/peps/pep-0282/.]]>
-
-
-
-W1202
-
-W1202
-
-(format_string.format(format_args...))". Such calls should use % formatting instead, but leave interpolation to the logging function by passing the parameters as arguments.]]>
-
-
-
-W1203
-
-W1203
-
-
-
-
-
-W1300
-
-W1300
-
-
-
-
-
-W1301
-
-W1301
-
-
-
-
-
-W1302
-
-W1302
-
-
-
-
-
-W1303
-
-W1303
-
-
-
-
-
-W1304
-
-W1304
-
-
-
-
-
-W1305
-
-W1305
-
-
-
-
-
-W1306
-
-W1306
-
-
-
-
-
-W1307
-
-W1307
-
-
-
-
-
-W1308
-
-W1308
-
-
-
-
-
-W1401
-
-W1401
-
-
-
-
-
-W1402
-
-W1402
-
-
-
-
-
-W1403
-
-W1403
-
-
-
-
-
-W1501
-
-W1501
-
-
-
-
-
-W1503
-
-W1503
-
-
-
-
-
-W1505
-
-W1505
-
-
-
-
-
-W1506
-
-W1506
-
-
-
-
-
-W1507
-
-W1507
-
-
-
-
-
-W1508
-
-W1508
-
-
-
-
-
-W1509
-
-W1509
-
-
-
-
-
-W1601
-
-W1601
-
-
-
-
-
-W1602
-
-W1602
-
-
-
-
-
-W1603
-
-W1603
-
-
-
-
-
-W1604
-
-W1604
-
-
-
-
-
-W1605
-
-W1605
-
-
-
-
-
-W1606
-
-W1606
-
-
-
-
-
-W1607
-
-W1607
-
-
-
-
-
-W1608
-
-W1608
-
-
-
-
-
-W1609
-
-W1609
-
-
-
-
-
-W1610
-
-W1610
-
-
-
-
-
-W1611
-
-W1611
-
-
-
-
-
-W1612
-
-W1612
-
-
-
-
-
-W1613
-
-W1613
-
-
-
-
-
-W1614
-
-W1614
-
-
-
-
-
-W1615
-
-W1615
-
-
-
-
-
-W1616
-
-W1616
-
-
-
-
-
-W1617
-
-W1617
-
-
-
-
-
-W1618
-
-W1618
-
-
-
-
-
-W1619
-
-W1619
-
-
-
-
-
-W1620
-
-W1620
-
-
-
-
-
-W1621
-
-W1621
-
-
-
-
-
-W1622
-
-W1622
-
-
-
-
-
-W1623
-
-W1623
-
-
-
-
-
-W1624
-
-W1624
-
-
-
-
-
-W1625
-
-W1625
-
-
-
-
-
-W1626
-
-W1626
-
-
-
-
-
-W1627
-
-W1627
-
-
-
-
-
-W1628
-
-W1628
-
-
-
-
-
-W1629
-
-W1629
-
-
-
-
-
-W1630
-
-W1630
-
-
-
-
-
-W1632
-
-W1632
-
-
-
-
-
-W1633
-
-W1633
-
-
-
-
-
-W1634
-
-W1634
-
-
-
-
-
-W1635
-
-W1635
-
-
-
-
-
-W1636
-
-W1636
-
-
-
-
-
-W1637
-
-W1637
-
-
-
-
-
-W1638
-
-W1638
-
-
-
-
-
-W1639
-
-W1639
-
-
-
-
-
-W1640
-
-W1640
-
-
-
-
-
-W1641
-
-W1641
-
-
-
-
-
-W1642
-
-W1642
-
-
-
-
-
-W1643
-
-W1643
-
-
-
-
-
-W1644
-
-W1644
-
-
-
-
-
-W1645
-
-W1645
-
-
-
-
-
-W1646
-
-W1646
-
-
-
-
-
-W1647
-
-W1647
-
-
-
-
-
-W1649
-
-W1649
-
-
-
-
-
-W1650
-
-W1650
-
-
-
-
-
-W1651
-
-W1651
-
-
-
-
-
-W1652
-
-W1652
-
-
-
-
-
-W1653
-
-W1653
-
-
-
-
-
-W1654
-
-W1654
-
-
-
-
-
-W1655
-
-W1655
-
-
-
-
-
-W1656
-
-W1656
-
-
-
-
-
-W1657
-
-W1657
-
-
-
-
-
-W1658
-
-W1658
-
-
-
-
-
-W1659
-
-W1659
-
-
-
-
-
-W1660
-
-W1660
-
-
-
-
-
-W1661
-
-W1661
-
-
-
-
-
-W1662
-
-W1662
-
-
-
-
-