|
12 | 12 |
|
13 | 13 | import python |
14 | 14 | import Variables.Definition |
| 15 | +import semmle.python.ApiGraphs |
| 16 | + |
| 17 | +private predicate is_pytest_fixture(Import imp, Variable name) { |
| 18 | + exists(Alias a, API::Node pytest_fixture, API::Node decorator | |
| 19 | + pytest_fixture = API::moduleImport("pytest").getMember("fixture") and |
| 20 | + // The additional `.getReturn()` is to account for the difference between |
| 21 | + // ``` |
| 22 | + // @pytest.fixture |
| 23 | + // def foo(): |
| 24 | + // ... |
| 25 | + // ``` |
| 26 | + // and |
| 27 | + // ``` |
| 28 | + // @pytest.fixture(some, args, here) |
| 29 | + // def foo(): |
| 30 | + // ... |
| 31 | + // ``` |
| 32 | + decorator in [pytest_fixture, pytest_fixture.getReturn()] and |
| 33 | + a = imp.getAName() and |
| 34 | + a.getAsname().(Name).getVariable() = name and |
| 35 | + a.getValue() = decorator.getReturn().getAValueReachableFromSource().asExpr() |
| 36 | + ) |
| 37 | +} |
15 | 38 |
|
16 | 39 | predicate global_name_used(Module m, string name) { |
17 | 40 | exists(Name u, GlobalVariable v | |
@@ -117,6 +140,7 @@ predicate unused_import(Import imp, Variable name) { |
117 | 140 | not all_not_understood(imp.getEnclosingModule()) and |
118 | 141 | not imported_module_used_in_doctest(imp) and |
119 | 142 | not imported_alias_used_in_typehint(imp, name) and |
| 143 | + not is_pytest_fixture(imp, name) and |
120 | 144 | // Only consider import statements that actually point-to something (possibly an unknown module). |
121 | 145 | // If this is not the case, it's likely that the import statement never gets executed. |
122 | 146 | imp.getAName().getValue().pointsTo(_) |
|
0 commit comments