Skip to content

Commit 5faa7e7

Browse files
committed
Python: Add ModuleValue::hasCompleteExportInfo
1 parent 3ffea59 commit 5faa7e7

3 files changed

Lines changed: 39 additions & 4 deletions

File tree

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ abstract class ModuleObjectInternal extends ObjectInternal {
7171
py_exports(this.getSourceModule(), name)
7272
}
7373

74+
/** Whether the complete set of names "exported" by this module can be accurately determined */
75+
abstract predicate hasCompleteExportInfo();
76+
7477
override predicate isNotSubscriptedType() { any() }
7578

7679
}
@@ -125,6 +128,10 @@ class BuiltinModuleObjectInternal extends ModuleObjectInternal, TBuiltinModuleOb
125128
none()
126129
}
127130

131+
override predicate hasCompleteExportInfo() {
132+
any()
133+
}
134+
128135
}
129136

130137
/** A class representing packages */
@@ -230,6 +237,12 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
230237
exists(this.submodule(name))
231238
}
232239

240+
override predicate hasCompleteExportInfo() {
241+
242+
not exists(this.getInitModule())
243+
or
244+
this.getInitModule().hasCompleteExportInfo()
245+
}
233246
}
234247

235248
/** A class representing Python modules */
@@ -300,6 +313,17 @@ class PythonModuleObjectInternal extends ModuleObjectInternal, TPythonModule {
300313
)
301314
}
302315

316+
override predicate hasCompleteExportInfo() {
317+
exists(Module m |
318+
m = this.getSourceModule() |
319+
not exists(Call modify, Attribute attr, GlobalVariable all |
320+
modify.getScope() = m and modify.getFunc() = attr and
321+
all.getId() = "__all__" |
322+
attr.getObject().(Name).uses(all)
323+
)
324+
)
325+
}
326+
303327
}
304328

305329
/** A class representing a module that is missing from the DB, but inferred to exists from imports. */
@@ -354,6 +378,9 @@ class AbsentModuleObjectInternal extends ModuleObjectInternal, TAbsentModule {
354378
none()
355379
}
356380

381+
override predicate hasCompleteExportInfo() {
382+
none()
383+
}
357384
}
358385

359386
/** A class representing an attribute of a missing module. */
@@ -453,4 +480,3 @@ class AbsentModuleAttributeObjectInternal extends ObjectInternal, TAbsentModuleA
453480
override predicate isNotSubscriptedType() { any() }
454481

455482
}
456-

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ class ModuleValue extends Value {
150150
this instanceof PackageObjectInternal
151151
}
152152

153+
/** Whether the complete set of names "exported" by this module can be accurately determined */
154+
predicate hasCompleteExportInfo() {
155+
this.(ModuleObjectInternal).hasCompleteExportInfo()
156+
}
157+
153158
}
154159

155160
module Module {

python/ql/src/semmle/python/types/ModuleObject.qll

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,13 @@ abstract class ModuleObject extends Object {
8383
predicate exports(string name) {
8484
theModule().exports(name)
8585
}
86-
87-
/** Whether the complete set of names "exported" by this module can be accurately determined */
88-
abstract predicate exportsComplete();
86+
87+
/**
88+
* Whether the complete set of names "exported" by this module can be accurately determined
89+
*
90+
* DEPRECATED: Use ModuleValue::hasCompleteExportInfo instead
91+
*/
92+
deprecated abstract predicate exportsComplete();
8993

9094
/** Gets the short name of the module. For example the short name of module x.y.z is 'z' */
9195
string getShortName() {

0 commit comments

Comments
 (0)