Skip to content

Commit 88fba1e

Browse files
committed
SONARPY-1522 Change supported python versions
This entails changing the supported python versions of the serializer, as well as changing the Java code to reflect that
1 parent 15b760c commit 88fba1e

File tree

17 files changed

+190
-311
lines changed

17 files changed

+190
-311
lines changed

python-checks/src/test/java/org/sonar/python/checks/PytzUsageCheckTest.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,7 @@
2222
import org.sonar.plugins.python.api.PythonVersionUtils;
2323
import org.sonar.python.checks.utils.PythonCheckVerifier;
2424

25-
import static org.assertj.core.api.Assertions.assertThat;
26-
2725
class PytzUsageCheckTest {
28-
@Test
29-
void test_38() {
30-
ProjectPythonVersion.setCurrentVersions(EnumSet.of(PythonVersionUtils.Version.V_38));
31-
var issues = PythonCheckVerifier.issues("src/test/resources/checks/pytzUsage.py", new PytzUsageCheck());
32-
assertThat(issues)
33-
.isEmpty();
34-
}
35-
3626
@Test
3727
void test_39_310_311_312() {
3828
ProjectPythonVersion

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

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,12 @@
2626
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_311;
2727
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_312;
2828
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_313;
29-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_36;
30-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_37;
3129
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_38;
3230
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_39;
3331

3432
public class PythonVersionUtils {
3533

3634
public enum Version {
37-
V_36(3, 6, "36"),
38-
V_37(3, 7, "37"),
3935
V_38(3, 8, "38"),
4036
V_39(3, 9, "39"),
4137
V_310(3, 10, "310"),
@@ -78,27 +74,28 @@ public String toString() {
7874
}
7975
}
8076

77+
private static final Version MIN_SUPPORTED_VERSION = V_38;
78+
public static final Version MAX_SUPPORTED_VERSION = V_313;
79+
8180
/**
82-
* Note that versions between 3 and 3.6 are currently mapped to 3.6 because
81+
* Note that versions between 3 and 3.8 are currently mapped to 3.8 because
8382
* we don't take into account those version during typeshed symbols serialization
8483
*/
8584
private static final Map<String, Version> STRING_VERSION_MAP = Map.ofEntries(
86-
Map.entry("3.0", V_36),
87-
Map.entry("3.1", V_36),
88-
Map.entry("3.2", V_36),
89-
Map.entry("3.3", V_36),
90-
Map.entry("3.4", V_36),
91-
Map.entry("3.5", V_36),
92-
Map.entry("3.6", V_36),
93-
Map.entry("3.7", V_37),
85+
Map.entry("3.0", MIN_SUPPORTED_VERSION),
86+
Map.entry("3.1", MIN_SUPPORTED_VERSION),
87+
Map.entry("3.2", MIN_SUPPORTED_VERSION),
88+
Map.entry("3.3", MIN_SUPPORTED_VERSION),
89+
Map.entry("3.4", MIN_SUPPORTED_VERSION),
90+
Map.entry("3.5", MIN_SUPPORTED_VERSION),
91+
Map.entry("3.6", MIN_SUPPORTED_VERSION),
92+
Map.entry("3.7", MIN_SUPPORTED_VERSION),
9493
Map.entry("3.8", V_38),
9594
Map.entry("3.9", V_39),
9695
Map.entry("3.10", V_310),
9796
Map.entry("3.11", V_311),
9897
Map.entry("3.12", V_312),
9998
Map.entry("3.13", V_313));
100-
private static final Version MIN_SUPPORTED_VERSION = V_36;
101-
public static final Version MAX_SUPPORTED_VERSION = V_313;
10299
private static final Logger LOG = LoggerFactory.getLogger(PythonVersionUtils.class);
103100
public static final String PYTHON_VERSION_KEY = "sonar.python.version";
104101

@@ -175,12 +172,6 @@ public static boolean areSourcePythonVersionsGreaterOrEqualThan(Set<Version> sou
175172
.allMatch(version -> version.compare(required.major(), required.minor()) >= 0);
176173
}
177174

178-
/**
179-
* @return the set of versions which are supported but not serialized due to SONARPY-1522
180-
*/
181-
public static Set<Version> getNotSerializedVersions() {
182-
return EnumSet.of(V_312, V_313);
183-
}
184175

185176
private static void logErrorMessage(String propertyValue) {
186177
LOG.warn(

python-frontend/src/main/java/org/sonar/python/semantic/v2/typeshed/ProtoUtils.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.Set;
2323
import java.util.stream.Collectors;
2424
import java.util.stream.Stream;
25-
import org.sonar.plugins.python.api.PythonVersionUtils;
2625
import org.sonar.python.index.AmbiguousDescriptor;
2726
import org.sonar.python.index.Descriptor;
2827

@@ -50,13 +49,6 @@ static boolean isValidForPythonVersion(List<String> validForPythonVersions, Set<
5049
if (validForPythonVersions.isEmpty()) {
5150
return true;
5251
}
53-
// TODO: SONARPY-1522 - remove this workaround when we will have all the stubs for Python 3.12.
54-
Set<String> notSerializedVersions =
55-
PythonVersionUtils.getNotSerializedVersions().stream().map(PythonVersionUtils.Version::serializedValue).collect(Collectors.toSet());
56-
if (notSerializedVersions.containsAll(supportedPythonVersions)
57-
&& validForPythonVersions.contains(PythonVersionUtils.Version.V_311.serializedValue())) {
58-
return true;
59-
}
6052
HashSet<String> intersection = new HashSet<>(validForPythonVersions);
6153
intersection.retainAll(supportedPythonVersions);
6254
return !intersection.isEmpty();

python-frontend/src/main/java/org/sonar/python/types/TypeShed.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,8 @@ public static boolean isValidForProjectPythonVersion(List<String> validForPython
231231
if (validForPythonVersions.isEmpty()) {
232232
return true;
233233
}
234-
// TODO: SONARPY-1522 - remove this workaround when we will have all the stubs for Python 3.12.
235-
Set<String> notSerializedVersions = PythonVersionUtils.getNotSerializedVersions().stream().map(PythonVersionUtils.Version::serializedValue).collect(Collectors.toSet());
236-
if (notSerializedVersions.containsAll(supportedPythonVersions)
237-
&& validForPythonVersions.contains(PythonVersionUtils.Version.V_311.serializedValue())) {
238-
return true;
234+
if(supportedPythonVersions == null) {
235+
throw new IllegalStateException("supportedPythonVersion is uninitialized. Call builtinSymbols() first");
239236
}
240237
HashSet<String> intersection = new HashSet<>(validForPythonVersions);
241238
intersection.retainAll(supportedPythonVersions);

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

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,15 @@
3030
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_311;
3131
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_312;
3232
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_313;
33-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_36;
34-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_37;
35-
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_38;
3633
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_39;
34+
import static org.sonar.plugins.python.api.PythonVersionUtils.Version.V_38;
3735

3836
class PythonVersionUtilsTest {
3937

4038
@RegisterExtension
4139
public LogTesterJUnit5 logTester = new LogTesterJUnit5().setLevel(Level.DEBUG);
4240

43-
private static final List<PythonVersionUtils.Version> allVersions = List.of(V_36, V_37, V_38, V_39, V_310, V_311, V_312, V_313);
41+
private static final List<PythonVersionUtils.Version> allVersions = List.of(V_38, V_39, V_310, V_311, V_312, V_313);
4442

4543
@Test
4644
void supportedVersions() {
@@ -49,7 +47,7 @@ void supportedVersions() {
4947
assertThat(PythonVersionUtils.fromString("2.7")).hasSameElementsAs(allVersions);
5048
assertThat(PythonVersionUtils.fromString("2")).hasSameElementsAs(allVersions);
5149
assertThat(PythonVersionUtils.fromString("3")).hasSameElementsAs(allVersions);
52-
assertThat(PythonVersionUtils.fromString("3.8, 3.9")).containsExactlyInAnyOrder(V_38, V_39);
50+
assertThat(PythonVersionUtils.fromString("3.9, 3.10")).containsExactlyInAnyOrder(V_39, V_310);
5351
assertThat(PythonVersionUtils.fromString("2.7, 3.9")).hasSameElementsAs(allVersions);
5452
assertThat(PythonVersionUtils.fromString("3.10")).containsExactlyInAnyOrder(V_310);
5553
}
@@ -67,8 +65,8 @@ void version_out_of_range() {
6765

6866
@Test
6967
void bugfix_versions() {
70-
assertThat(PythonVersionUtils.fromString("3.8.1")).containsExactlyInAnyOrder(V_38);
71-
assertThat(logTester.logs(Level.WARN)).contains("No explicit support for version 3.8.1. Python version has been set to 3.8.");
68+
assertThat(PythonVersionUtils.fromString("3.9.1")).containsExactlyInAnyOrder(V_39);
69+
assertThat(logTester.logs(Level.WARN)).contains("No explicit support for version 3.9.1. Python version has been set to 3.9.");
7270
assertThat(PythonVersionUtils.fromString("3.11.1")).containsExactlyInAnyOrder(V_311);
7371
assertThat(PythonVersionUtils.fromString("3.12.1")).containsExactlyInAnyOrder(V_312);
7472
}
@@ -83,8 +81,8 @@ void error_while_parsing_version() {
8381
@Test
8482
void isPythonVersionGreaterOrEqualThan() {
8583
assertFalse(PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan(Set.of(), V_39));
86-
assertFalse(PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan(Set.of(V_36, V_38), V_39));
87-
assertFalse(PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan(Set.of(V_36, V_310), V_39));
84+
assertFalse(PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan(Set.of(V_311, V_312), V_313));
85+
assertFalse(PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan(Set.of(V_310, V_312), V_311));
8886
assertTrue(PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan(Set.of(V_39), V_39));
8987
assertTrue(PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan(Set.of(V_39, V_310), V_39));
9088
assertTrue(PythonVersionUtils.areSourcePythonVersionsGreaterOrEqualThan(Set.of(V_312, V_310), V_39));

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

Lines changed: 83 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.protobuf.TextFormat;
2020
import java.util.Collections;
2121
import java.util.HashSet;
22+
import org.junit.jupiter.api.BeforeEach;
2223
import org.junit.jupiter.api.Test;
2324
import org.sonar.plugins.python.api.symbols.AmbiguousSymbol;
2425
import org.sonar.plugins.python.api.symbols.ClassSymbol;
@@ -36,6 +37,10 @@
3637
import static org.sonar.python.PythonTestUtils.parse;
3738

3839
class ClassSymbolImplTest {
40+
@BeforeEach
41+
void setup() {
42+
TypeShed.resetBuiltinSymbols();
43+
}
3944

4045
@Test
4146
void hasUnresolvedTypeHierarchy() {
@@ -228,13 +233,14 @@ void removeUsages() {
228233

229234
@Test
230235
void from_protobuf() throws TextFormat.ParseException {
231-
String protobuf =
232-
"name: \"A\"\n" +
233-
"fully_qualified_name: \"mod.A\"\n" +
234-
"super_classes: \"builtins.object\"\n" +
235-
"has_decorators: true\n" +
236-
"has_metaclass: true\n" +
237-
"metaclass_name: \"abc.ABCMeta\"";
236+
String protobuf = """
237+
name: "A"
238+
fully_qualified_name: "mod.A"
239+
super_classes: "builtins.object"
240+
has_decorators: true
241+
has_metaclass: true
242+
metaclass_name: "abc.ABCMeta"
243+
""";
238244
ClassSymbolImpl classSymbol = new ClassSymbolImpl(classSymbol(protobuf), "mod");
239245
assertThat(classSymbol.name()).isEqualTo("A");
240246
assertThat(classSymbol.fullyQualifiedName()).isEqualTo("mod.A");
@@ -246,95 +252,100 @@ void from_protobuf() throws TextFormat.ParseException {
246252

247253
@Test
248254
void from_protobuf_instance_method() throws TextFormat.ParseException {
249-
String protobuf =
250-
"name: \"A\"\n" +
251-
"fully_qualified_name: \"mod.A\"\n" +
252-
"super_classes: \"builtins.object\"\n" +
253-
"methods {\n" +
254-
" name: \"foo\"\n" +
255-
" fully_qualified_name: \"mod.A.foo\"\n" +
256-
" parameters {\n" +
257-
" name: \"self\"\n" +
258-
" kind: POSITIONAL_OR_KEYWORD\n" +
259-
" }\n" +
260-
" has_decorators: true\n" +
261-
"}";
255+
String protobuf = """
256+
name: "A"
257+
fully_qualified_name: "mod.A"
258+
super_classes: "builtins.object"
259+
methods {
260+
name: "foo"
261+
fully_qualified_name: "mod.A.foo"
262+
parameters {
263+
name: "self"
264+
kind: POSITIONAL_OR_KEYWORD
265+
}
266+
has_decorators: true
267+
}
268+
""";
262269
ClassSymbolImpl classSymbol = new ClassSymbolImpl(classSymbol(protobuf), "mod");
263270
FunctionSymbol foo = (FunctionSymbol) classSymbol.declaredMembers().iterator().next();
264271
assertThat(foo.isInstanceMethod()).isTrue();
265272
}
266273

267274
@Test
268275
void from_protobuf_class_method() throws TextFormat.ParseException {
269-
String protobuf =
270-
"name: \"A\"\n" +
271-
"fully_qualified_name: \"mod.A\"\n" +
272-
"super_classes: \"builtins.object\"\n" +
273-
"methods {\n" +
274-
" name: \"foo\"\n" +
275-
" fully_qualified_name: \"mod.A.foo\"\n" +
276-
" parameters {\n" +
277-
" name: \"cls\"\n" +
278-
" kind: POSITIONAL_OR_KEYWORD\n" +
279-
" }\n" +
280-
" has_decorators: true\n" +
281-
" is_class_method: true\n" +
282-
"}";
276+
String protobuf = """
277+
name: "A"
278+
fully_qualified_name: "mod.A"
279+
super_classes: "builtins.object"
280+
methods {
281+
name: "foo"
282+
fully_qualified_name: "mod.A.foo"
283+
parameters {
284+
name: "cls"
285+
kind: POSITIONAL_OR_KEYWORD
286+
}
287+
has_decorators: true
288+
is_class_method: true
289+
}
290+
""";
283291
ClassSymbolImpl classSymbol = new ClassSymbolImpl(classSymbol(protobuf), "mod");
284292
FunctionSymbol foo = (FunctionSymbol) classSymbol.declaredMembers().iterator().next();
285293
assertThat(foo.isInstanceMethod()).isFalse();
286294
}
287295

288296
@Test
289297
void from_protobuf_static_method() throws TextFormat.ParseException {
290-
String protobuf =
291-
"name: \"A\"\n" +
292-
"fully_qualified_name: \"mod.A\"\n" +
293-
"super_classes: \"builtins.object\"\n" +
294-
"methods {\n" +
295-
" name: \"foo\"\n" +
296-
" fully_qualified_name: \"mod.A.foo\"\n" +
297-
" parameters {\n" +
298-
" name: \"x\"\n" +
299-
" kind: POSITIONAL_OR_KEYWORD\n" +
300-
" }\n" +
301-
" has_decorators: true\n" +
302-
" is_static: true\n" +
303-
"}";
298+
String protobuf = """
299+
name: "A"
300+
fully_qualified_name: "mod.A"
301+
super_classes: "builtins.object"
302+
methods {
303+
name: "foo"
304+
fully_qualified_name: "mod.A.foo"
305+
parameters {
306+
name: "x"
307+
kind: POSITIONAL_OR_KEYWORD
308+
}
309+
has_decorators: true
310+
is_static: true
311+
}
312+
""";
304313
ClassSymbolImpl classSymbol = new ClassSymbolImpl(classSymbol(protobuf), "mod");
305314
FunctionSymbol foo = (FunctionSymbol) classSymbol.declaredMembers().iterator().next();
306315
assertThat(foo.isInstanceMethod()).isFalse();
307316
}
308317

309318
@Test
310319
void overloaded_methods() throws TextFormat.ParseException {
311-
String protobuf =
312-
"name: \"A\"\n" +
313-
"fully_qualified_name: \"mod.A\"\n" +
314-
"super_classes: \"builtins.object\"\n" +
315-
"methods {\n" +
316-
" name: \"foo\"\n" +
317-
" fully_qualified_name: \"mod.A.foo\"\n" +
318-
" valid_for: \"36\"\n" +
319-
"}\n" +
320-
"overloaded_methods {\n" +
321-
" name: \"foo\"\n" +
322-
" fullname: \"mod.A.foo\"\n" +
323-
" valid_for: \"39\"\n" +
324-
" definitions {\n" +
325-
" name: \"foo\"\n" +
326-
" fully_qualified_name: \"mod.A.foo\"\n" +
327-
" has_decorators: true\n" +
328-
" }\n" +
329-
" definitions {\n" +
330-
" name: \"foo\"\n" +
331-
" fully_qualified_name: \"mod.A.foo\"\n" +
332-
" }\n" +
333-
"}\n";
320+
String protobuf = """
321+
name: "A"
322+
fully_qualified_name: "mod.A"
323+
super_classes: "builtins.object"
324+
methods {
325+
name: "foo"
326+
fully_qualified_name: "mod.A.foo"
327+
valid_for: "39"
328+
}
329+
overloaded_methods {
330+
name: "foo"
331+
fullname: "mod.A.foo"
332+
valid_for: "310"
333+
definitions {
334+
name: "foo"
335+
fully_qualified_name: "mod.A.foo"
336+
has_decorators: true
337+
}
338+
definitions {
339+
name: "foo"
340+
fully_qualified_name: "mod.A.foo"
341+
}
342+
}
343+
344+
""";
334345
ClassSymbolImpl classSymbol = new ClassSymbolImpl(classSymbol(protobuf), "mod");
335346
Symbol foo = classSymbol.resolveMember("foo").get();
336347
assertThat(foo.is(Symbol.Kind.AMBIGUOUS)).isTrue();
337-
assertThat(((SymbolImpl) foo).validForPythonVersions()).containsExactlyInAnyOrder("36", "39");
348+
assertThat(((SymbolImpl) foo).validForPythonVersions()).containsExactlyInAnyOrder("39", "310");
338349
}
339350

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

0 commit comments

Comments
 (0)