Skip to content

Commit 8ffcff0

Browse files
committed
Python: Add example of top-level module shadowing stdlib
Although this test is added under the `wrong` folder, the current results from this CodeQL test is actually correct (compared with the Python interpreter). However, they don't match what the extractor does when invoked with `codeql database create`. Since I deemed it "more than an easy fix" to change the extractor behavior for `codeql database create` to match the real python behavior, and it turned out to be quite a challenge to change the extractor behavior for all tests, I'm just going to make THIS ONE test-case behave like the extractor will with `codeql database create`... This is a first commit, to show how the extractor works with qltest by default. Inspired by the debugging in github#4640
1 parent 2945ead commit 8ffcff0

File tree

13 files changed

+67
-0
lines changed

13 files changed

+67
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| Local module | cmd.py:0:0:0:0 | Module cmd | referenced in external file called | pdb.py |
2+
| Local module | cmd.py:0:0:0:0 | Module cmd | referenced in local file called | test_ok.py |
3+
| Local module | unique_name.py:0:0:0:0 | Module unique_name | referenced in local file called | unique_name_use.py |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import python
2+
3+
from ModuleValue mv, ControlFlowNode ref, string local_external
4+
where
5+
ref = mv.getAReference() and
6+
exists(mv.getScope().getFile().getRelativePath()) and
7+
(
8+
if exists(ref.getLocation().getFile().getRelativePath())
9+
then local_external = "local"
10+
else local_external = "external"
11+
)
12+
select "Local module", mv, "referenced in " + local_external + " file called",
13+
ref.getLocation().getFile().getShortName()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| cmd.py:0:0:0:0 | Module cmd |
2+
| test_fail.py:0:0:0:0 | Module test_fail |
3+
| test_ok.py:0:0:0:0 | Module test_ok |
4+
| unique_name.py:0:0:0:0 | Module unique_name |
5+
| unique_name_use.py:0:0:0:0 | Module unique_name_use |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import python
2+
3+
from Module m
4+
where exists(m.getFile().getRelativePath())
5+
select m
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| Module 'cmd' (local, not in stdlib, not missing) referenced in local file | test_ok.py:1 |
2+
| Module 'pdb' (external, in stdlib, not missing) referenced in local file | test_fail.py:3 |
3+
| Module 'unique_name' (local, not in stdlib, not missing) referenced in local file | unique_name_use.py:1 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import python
2+
3+
from ModuleValue mv, ControlFlowNode ref, string in_stdlib, string local_external, string is_missing
4+
where
5+
ref = mv.getAReference() and
6+
exists(ref.getLocation().getFile().getRelativePath()) and
7+
(
8+
if mv.getScope().getFile().inStdlib()
9+
then in_stdlib = "in stdlib"
10+
else in_stdlib = "not in stdlib"
11+
) and
12+
(
13+
if exists(mv.getScope().getFile().getRelativePath())
14+
then local_external = "local"
15+
else local_external = "external"
16+
) and
17+
(if mv.isAbsent() then is_missing = "missing" else is_missing = "not missing")
18+
select "Module '" + mv.getName() + "' (" + local_external + ", " + in_stdlib + ", " + is_missing +
19+
") referenced in local file", ref.getLocation().toString()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
This test shows how we handle modules the shadow a module in the standard library.
2+
3+
We manually replicate the behavior of `codeql database create --source-root <src-dir>`, which will use `-R <src-dir>`. By default, the way qltest invokes the extractor will cause different behavior. Therefore, we also need to move our code outside of the top-level folder, and it lives in `code/`.
4+
5+
Because we have a `cmd.py` file, whenever the python interpreter sees `import cmd`, that is the file that will be used! --
6+
7+
* `python test_ok.py` works as intended, and prints `Foo`
8+
* `python test_fail.py` raises an exception, since it imports `pdb.py` from the standard library, which (at least in Python 3.8) tries to import `cmd.py` from the standard library, but instead is served our `cmd.py` module. Therefore it fails with `AttributeError: module 'cmd' has no attribute 'Cmd'`
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
foo = "Foo"
2+
print("my own cmd imported")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
semmle-extractor-options: --max-import-depth=2
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# we import `pdb` which import the `cmd` module from the standard library
2+
# and allows us to set --max-import-depth=2, to make the test run fast
3+
import pdb

0 commit comments

Comments
 (0)