Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3e7e963

Browse files
committed
Python: Add ModuleValue.{isUsedAsModule, isUsedAsScript}
and a few test cases
1 parent b4ab0b5 commit 3e7e963

8 files changed

Lines changed: 59 additions & 1 deletion

File tree

python/ql/src/Statements/TopLevelPrint.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ from Stmt p
3535
where
3636
is_print_stmt(p) and
3737
// TODO: Need to discuss how we would like to handle ModuleObject.getKind in the glorious future
38-
exists(ModuleObject m | m.getModule() = p.getScope() and m.getKind() = "module") and
38+
exists(ModuleValue m | m.getScope() = p.getScope() and m.isUsedAsModule()) and
3939
not exists(If i | main_eq_name(i) and i.getASubStatement().getASubStatement*() = p)
4040
select p, "Print statement may execute during import."

python/ql/src/semmle/python/objects/ObjectAPI.qll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,32 @@ class ModuleValue extends Value {
187187
result.importedAs(this.getScope().getAnImportedModuleName())
188188
}
189189

190+
/** When used as a normal module (for example, imported and used by other modules) */
191+
predicate isUsedAsModule() {
192+
this.isBuiltin()
193+
or
194+
this.isPackage()
195+
or
196+
exists(ImportingStmt i | this.importedAs(i.getAnImportedModuleName()))
197+
or
198+
this.getPath().getBaseName() = "__init__.py"
199+
}
200+
201+
/** When used (exclusively) as a script (will not include normal modules that can also be run as a script) */
202+
predicate isUsedAsScript() {
203+
not isUsedAsModule() and
204+
(
205+
not this.getPath().getExtension() = "py"
206+
or
207+
exists(If i, Name name, StrConst main, Cmpop op |
208+
i.getScope() = this.getScope() and
209+
op instanceof Eq and
210+
i.getTest().(Compare).compares(name, op, main) and
211+
name.getId() = "__name__" and main.getText() = "__main__"
212+
)
213+
// TODO: Add she-bang handling
214+
)
215+
}
190216
}
191217

192218
module Module {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| file://:0:0:0:0 | Module builtins | isUsedAsModule |
2+
| file://:0:0:0:0 | Module sys | isUsedAsModule |
3+
| imported.py:0:0:0:0 | Module imported | isUsedAsModule |
4+
| main.py:0:0:0:0 | Module main | isUsedAsScript |
5+
| mybin:0:0:0:0 | Script script | isUsedAsScript |
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import python
2+
3+
from ModuleValue mv, string usage
4+
where
5+
mv.isUsedAsModule() and usage = "isUsedAsModule"
6+
or
7+
mv.isUsedAsScript() and usage = "isUsedAsScript"
8+
or
9+
not mv.isUsedAsModule() and
10+
not mv.isUsedAsScript() and
11+
usage = "<UNKNOWN>"
12+
select mv, usage
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def func():
2+
pass
3+
4+
if __name__ == "__main__":
5+
print("I could have done something interesting...")
6+
print("but I didn't")
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import imported
2+
3+
if __name__ == "__main__":
4+
imported.func()
5+
print('Done')
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle-extractor-options: -F script
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env python
2+
3+
print('Under construction :)')

0 commit comments

Comments
 (0)