Skip to content

Commit f69846c

Browse files
authored
SONARPY-1777 S1128: Do not raise an unused import on from sklearn.experimental (#1766)
1 parent 2cf30df commit f69846c

File tree

2 files changed

+14
-6
lines changed

2 files changed

+14
-6
lines changed

python-checks/src/main/java/org/sonar/python/checks/UnusedImportCheck.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import java.util.HashMap;
2323
import java.util.Map;
24+
import java.util.Optional;
2425
import java.util.Set;
2526
import org.sonar.check.Rule;
2627
import org.sonar.plugins.python.api.PythonVisitorCheck;
@@ -34,12 +35,12 @@
3435
import org.sonar.plugins.python.api.tree.Tree;
3536
import org.sonar.plugins.python.api.tree.Trivia;
3637

37-
3838
@Rule(key = "S1128")
3939
public class UnusedImportCheck extends PythonVisitorCheck {
4040

4141
private static final String MESSAGE = "Remove this unused import.";
4242
private static final Set<String> ALLOWED_MODULES = Set.of("__future__", "typing", "typing_extensions");
43+
private static final Set<String> ALLOWED_FQN_PREFIX = Set.of("sklearn.experimental.");
4344

4445
private final Map<String, Name> unusedImports = new HashMap<>();
4546

@@ -79,11 +80,14 @@ public void visitImportFrom(ImportFrom importFrom) {
7980
for (AliasedName aliasedName : importFrom.importedNames()) {
8081
Name alias = aliasedName.alias();
8182
var importedName = alias != null ? alias : aliasedName.dottedName().names().get(0);
82-
var importedSymbol = importedName.symbol();
83-
// defensive programming: imported symbol should never be null, because it always binds a name
84-
if (importedSymbol != null && importedSymbol.usages().stream().filter(u -> !u.isBindingUsage()).findFirst().isEmpty()) {
85-
unusedImports.put(importedName.name(), importedName);
86-
}
83+
Optional.ofNullable(importedName.symbol())
84+
.filter(symbol -> symbol.usages().stream().filter(u -> !u.isBindingUsage()).findFirst().isEmpty())
85+
.filter(symbol ->
86+
Optional.ofNullable(symbol.fullyQualifiedName())
87+
.map(fqn -> ALLOWED_FQN_PREFIX.stream().noneMatch(fqn::startsWith))
88+
.orElse(true)
89+
)
90+
.ifPresent(symbol -> unusedImports.put(importedName.name(), importedName));
8791
}
8892
super.visitImportFrom(importFrom);
8993
}

python-checks/src/test/resources/checks/unusedImport/unusedImport.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,7 @@ def import_inside_function():
3838
from my_module import if_import # Compliant
3939

4040
if_import()
41+
42+
from sklearn.experimental import enable_iterative_imputer
43+
from sklearn.experimental import pjdfgpojdgf as something
44+
from sklearn.impute import IterativeImputer # Noncompliant

0 commit comments

Comments
 (0)