Skip to content

Commit 2b4b5ee

Browse files
SONARPY-1392 Update the list of supported Python versions (#1501)
1 parent cd6bbba commit 2b4b5ee

File tree

5 files changed

+55
-50
lines changed

5 files changed

+55
-50
lines changed

python-frontend/src/main/java/org/sonar/plugins/python/api/PythonVersionUtils.java

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@
2727
import org.sonar.api.utils.log.Logger;
2828
import org.sonar.api.utils.log.Loggers;
2929

30-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_27;
3130
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_310;
32-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_35;
31+
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_311;
3332
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_36;
3433
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_37;
3534
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_38;
@@ -38,13 +37,12 @@
3837
public class PythonVersionUtils {
3938

4039
public enum Version {
41-
V_27(2, 7, "27"),
42-
V_35(3, 5, "35"),
4340
V_36(3, 6, "36"),
4441
V_37(3, 7, "37"),
4542
V_38(3, 8, "38"),
4643
V_39(3, 9, "39"),
47-
V_310(3, 10, "310");
44+
V_310(3, 10, "310"),
45+
V_311(3, 11, "311");
4846

4947
private final int major;
5048
private final int minor;
@@ -82,28 +80,25 @@ public String toString() {
8280
}
8381

8482
/**
85-
* Note that versions between 3 and 3.5 are currently mapped to 3.5 because
83+
* Note that versions between 3 and 3.6 are currently mapped to 3.6 because
8684
* we don't take into account those version during typeshed symbols serialization
8785
*/
88-
private static final Map<String, Version> STRING_VERSION_MAP = new HashMap<>();
89-
static {
90-
STRING_VERSION_MAP.put("2", V_27);
91-
STRING_VERSION_MAP.put("2.7", V_27);
92-
STRING_VERSION_MAP.put("3", V_35);
93-
STRING_VERSION_MAP.put("3.0", V_35);
94-
STRING_VERSION_MAP.put("3.1", V_35);
95-
STRING_VERSION_MAP.put("3.2", V_35);
96-
STRING_VERSION_MAP.put("3.3", V_35);
97-
STRING_VERSION_MAP.put("3.4", V_35);
98-
STRING_VERSION_MAP.put("3.5", V_35);
99-
STRING_VERSION_MAP.put("3.6", V_36);
100-
STRING_VERSION_MAP.put("3.7", V_37);
101-
STRING_VERSION_MAP.put("3.8", V_38);
102-
STRING_VERSION_MAP.put("3.9", V_39);
103-
STRING_VERSION_MAP.put("3.10", V_310);
104-
}
105-
private static final Version MIN_SUPPORTED_VERSION = V_27;
106-
private static final Version MAX_SUPPORTED_VERSION = V_310;
86+
private static final Map<String, Version> STRING_VERSION_MAP = Map.ofEntries(
87+
Map.entry("3.0", V_36),
88+
Map.entry("3.1", V_36),
89+
Map.entry("3.2", V_36),
90+
Map.entry("3.3", V_36),
91+
Map.entry("3.4", V_36),
92+
Map.entry("3.5", V_36),
93+
Map.entry("3.6", V_36),
94+
Map.entry("3.7", V_37),
95+
Map.entry("3.8", V_38),
96+
Map.entry("3.9", V_39),
97+
Map.entry("3.10", V_310),
98+
Map.entry("3.11", V_311)
99+
);
100+
private static final Version MIN_SUPPORTED_VERSION = V_36;
101+
private static final Version MAX_SUPPORTED_VERSION = V_311;
107102
private static final Logger LOG = Loggers.get(PythonVersionUtils.class);
108103
public static final String PYTHON_VERSION_KEY = "sonar.python.version";
109104

@@ -118,6 +113,10 @@ public static Set<Version> fromString(String propertyValue) {
118113
Set<Version> pythonVersions = EnumSet.noneOf(Version.class);
119114
for (String versionValue : versions) {
120115
versionValue = versionValue.trim();
116+
if ("3".equals(versionValue)) {
117+
// Only 3.x stubs are supported
118+
return allVersions();
119+
}
121120
Version version = STRING_VERSION_MAP.get(versionValue);
122121
if (version != null) {
123122
pythonVersions.add(version);
@@ -146,6 +145,10 @@ private static boolean guessPythonVersion(Set<Version> pythonVersions, String ve
146145
logWarningGuessVersion(versionValue, guessedVersion);
147146
return true;
148147
}
148+
if (major < 3) {
149+
logWarningPython2(versionValue);
150+
return false;
151+
}
149152
if (MIN_SUPPORTED_VERSION.compare(major, minor) > 0) {
150153
pythonVersions.add(MIN_SUPPORTED_VERSION);
151154
logWarningGuessVersion(versionValue, MIN_SUPPORTED_VERSION);
@@ -172,4 +175,9 @@ private static void logWarningGuessVersion(String propertyValue, Version guessed
172175
String prefix = "No explicit support for version %s. Python version has been set to %s.";
173176
LOG.warn(String.format(Locale.ROOT, prefix, propertyValue, guessedVersion));
174177
}
178+
179+
private static void logWarningPython2(String propertyValue) {
180+
String prefix = "No explicit support for version %s. Support for Python versions prior to 3 is deprecated.";
181+
LOG.warn(String.format(Locale.ROOT, prefix, propertyValue));
182+
}
175183
}

python-frontend/src/test/java/org/sonar/plugins/python/api/PythonVersionUtilsTest.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,8 @@
2424
import org.sonar.api.utils.log.LoggerLevel;
2525

2626
import static org.assertj.core.api.Assertions.assertThat;
27-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_27;
27+
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_311;
2828
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_310;
29-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_35;
3029
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_36;
3130
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_37;
3231
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_38;
@@ -39,36 +38,37 @@ public class PythonVersionUtilsTest {
3938

4039
@Test
4140
public void supportedVersions() {
42-
assertThat(PythonVersionUtils.fromString("")).containsExactlyInAnyOrder(V_27, V_35, V_36, V_37, V_38, V_39, V_310);
43-
assertThat(PythonVersionUtils.fromString(",")).containsExactlyInAnyOrder(V_27, V_35, V_36, V_37, V_38, V_39, V_310);
44-
assertThat(PythonVersionUtils.fromString("2.7")).containsExactlyInAnyOrder(V_27);
45-
assertThat(PythonVersionUtils.fromString("2")).containsExactlyInAnyOrder(V_27);
46-
assertThat(PythonVersionUtils.fromString("3")).containsExactlyInAnyOrder(V_35);
41+
assertThat(PythonVersionUtils.fromString("")).containsExactlyInAnyOrder(V_36, V_37, V_38, V_39, V_310, V_311);
42+
assertThat(PythonVersionUtils.fromString(",")).containsExactlyInAnyOrder(V_36, V_37, V_38, V_39, V_310, V_311);
43+
assertThat(PythonVersionUtils.fromString("2.7")).containsExactlyInAnyOrder(V_36, V_37, V_38, V_39, V_310, V_311);
44+
assertThat(PythonVersionUtils.fromString("2")).containsExactlyInAnyOrder(V_36, V_37, V_38, V_39, V_310, V_311);
45+
assertThat(PythonVersionUtils.fromString("3")).containsExactlyInAnyOrder(V_36, V_37, V_38, V_39, V_310, V_311);
4746
assertThat(PythonVersionUtils.fromString("3.8, 3.9")).containsExactlyInAnyOrder(V_38, V_39);
48-
assertThat(PythonVersionUtils.fromString("2.7, 3.9")).containsExactlyInAnyOrder(V_27, V_39);
47+
assertThat(PythonVersionUtils.fromString("2.7, 3.9")).containsExactlyInAnyOrder(V_36, V_37, V_38, V_39, V_310, V_311);
4948
assertThat(PythonVersionUtils.fromString("3.10")).containsExactlyInAnyOrder(V_310);
5049
}
5150

5251
@Test
5352
public void version_out_of_range() {
54-
assertThat(PythonVersionUtils.fromString("4")).containsExactlyInAnyOrder(V_310);
55-
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 4. Python version has been set to 3.10.");
56-
assertThat(PythonVersionUtils.fromString("1")).containsExactlyInAnyOrder(V_27);
57-
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 1. Python version has been set to 2.7.");
58-
assertThat(PythonVersionUtils.fromString("3.11")).containsExactlyInAnyOrder(V_310);
59-
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 3.11. Python version has been set to 3.10.");
53+
assertThat(PythonVersionUtils.fromString("4")).containsExactlyInAnyOrder(V_311);
54+
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 4. Python version has been set to 3.11.");
55+
assertThat(PythonVersionUtils.fromString("1")).containsExactlyInAnyOrder(V_36, V_37, V_38, V_39, V_310, V_311);
56+
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 1. Support for Python versions prior to 3 is deprecated.");
57+
assertThat(PythonVersionUtils.fromString("3.12")).containsExactlyInAnyOrder(V_311);
58+
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 3.12. Python version has been set to 3.11.");
59+
assertThat(PythonVersionUtils.fromString("3.11")).containsExactlyInAnyOrder(V_311);
6060
}
6161

6262
@Test
6363
public void bugfix_versions() {
6464
assertThat(PythonVersionUtils.fromString("3.8.1")).containsExactlyInAnyOrder(V_38);
6565
assertThat(logTester.logs(LoggerLevel.WARN)).contains("No explicit support for version 3.8.1. Python version has been set to 3.8.");
66-
assertThat(PythonVersionUtils.fromString("3.11.1")).containsExactlyInAnyOrder(V_310);
66+
assertThat(PythonVersionUtils.fromString("3.11.1")).containsExactlyInAnyOrder(V_311);
6767
}
6868

6969
@Test
7070
public void error_while_parsing_version() {
71-
assertThat(PythonVersionUtils.fromString("foo")).containsExactlyInAnyOrder(V_27, V_35, V_36, V_37, V_38, V_39, V_310);
71+
assertThat(PythonVersionUtils.fromString("foo")).containsExactlyInAnyOrder(V_36, V_37, V_38, V_39, V_310, V_311);
7272
assertThat(logTester.logs(LoggerLevel.WARN)).contains("Error while parsing value of parameter 'sonar.python.version' (foo). Versions must be specified as MAJOR_VERSION.MIN.VERSION (e.g. \"3.7, 3.8\")");
7373
}
7474
}

python-frontend/src/test/java/org/sonar/python/semantic/ClassSymbolImplTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ public void overloaded_methods() throws TextFormat.ParseException {
318318
"methods {\n" +
319319
" name: \"foo\"\n" +
320320
" fully_qualified_name: \"mod.A.foo\"\n" +
321-
" valid_for: \"27\"\n" +
321+
" valid_for: \"36\"\n" +
322322
"}\n" +
323323
"overloaded_methods {\n" +
324324
" name: \"foo\"\n" +
@@ -337,7 +337,7 @@ public void overloaded_methods() throws TextFormat.ParseException {
337337
ClassSymbolImpl classSymbol = new ClassSymbolImpl(classSymbol(protobuf), "mod");
338338
Symbol foo = classSymbol.resolveMember("foo").get();
339339
assertThat(foo.is(Symbol.Kind.AMBIGUOUS)).isTrue();
340-
assertThat(((SymbolImpl) foo).validForPythonVersions()).containsExactlyInAnyOrder("27", "39");
340+
assertThat(((SymbolImpl) foo).validForPythonVersions()).containsExactlyInAnyOrder("36", "39");
341341
}
342342

343343
private static SymbolsProtos.ClassSymbol classSymbol(String protobuf) throws TextFormat.ParseException {

python-frontend/src/test/java/org/sonar/python/types/TypeShedTest.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import org.sonar.plugins.python.api.symbols.Symbol;
4141
import org.sonar.plugins.python.api.symbols.Symbol.Kind;
4242
import org.sonar.python.semantic.AmbiguousSymbolImpl;
43-
import org.sonar.python.semantic.ClassSymbolImpl;
4443
import org.sonar.python.semantic.FunctionSymbolImpl;
4544
import org.sonar.python.semantic.SymbolImpl;
4645
import org.sonar.python.types.protobuf.SymbolsProtos;
@@ -91,9 +90,6 @@ public void str() {
9190
assertThat(strClass.resolveMember("removeprefix")).isEmpty();
9291
assertThat(strClass.resolveMember("removesuffix")).isEmpty();
9392

94-
setPythonVersions(PythonVersionUtils.fromString("2.7"));
95-
96-
assertThatIllegalArgumentException().isThrownBy( () -> TypeShed.typeShedClass("str"));
9793
setPythonVersions(PythonVersionUtils.allVersions());
9894
}
9995

@@ -432,7 +428,8 @@ public void pythonVersions() {
432428
// python 2
433429
setPythonVersions(PythonVersionUtils.fromString("2.7"));
434430
range = TypeShed.builtinSymbols().get("range");
435-
assertThat(range).isNull();
431+
// Python 3 symbols are returned, as no dedicated stubs for 2.7 are available anymore
432+
assertThat(range).isNotNull();
436433

437434
// python 3
438435
setPythonVersions(PythonVersionUtils.fromString("3.8"));

sonar-python-plugin/src/main/java/org/sonar/plugins/python/PythonSensor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ public final class PythonSensor implements Sensor {
6363
private final AnalysisWarningsWrapper analysisWarnings;
6464
private static final Logger LOG = Loggers.get(PythonSensor.class);
6565
static final String UNSET_VERSION_WARNING =
66-
"Your code is analyzed as compatible with python 2 and 3 by default. This will prevent the detection of issues specific to python 2 or python 3." +
67-
" You can get a more precise analysis by setting a python version in your configuration via the parameter \"sonar.python.version\"";
66+
"Your code is analyzed as compatible with all Python 3 versions by default." +
67+
" You can get a more precise analysis by setting the exact Python version in your configuration via the parameter \"sonar.python.version\"";
6868

6969
/**
7070
* Constructor to be used by pico if neither PythonCustomRuleRepository nor PythonIndexer are to be found and injected.

0 commit comments

Comments
 (0)