@@ -179,21 +179,6 @@ private predicate legalDottedName(string name) {
179
179
bindingset [ name]
180
180
private predicate legalShortName ( string name ) { name .regexpMatch ( "(\\p{L}|_)(\\p{L}|\\d|_)*" ) }
181
181
182
- /**
183
- * Holds if `f` is potentially a source package.
184
- * Does it have an __init__.py file (or --respect-init=False for Python 2) and is it within the source archive?
185
- */
186
- private predicate isPotentialSourcePackage ( Folder f ) {
187
- f .getRelativePath ( ) != "" and
188
- isPotentialPackage ( f )
189
- }
190
-
191
- private predicate isPotentialPackage ( Folder f ) {
192
- exists ( f .getFile ( "__init__.py" ) )
193
- or
194
- py_flags_versioned ( "options.respect_init" , "False" , _) and major_version ( ) = 2 and exists ( f )
195
- }
196
-
197
182
private string moduleNameFromBase ( Container file ) {
198
183
// We used to also require `isPotentialPackage(f)` to hold in this case,
199
184
// but we saw modules not getting resolved because their folder did not
@@ -236,31 +221,87 @@ private predicate transitively_imported_from_entry_point(File file) {
236
221
)
237
222
}
238
223
224
+ private predicate isRegularPackage ( Folder f , string name ) {
225
+ legalShortName ( name ) and
226
+ name = f .getStem ( ) and
227
+ exists ( f .getFile ( "__init__.py" ) )
228
+ }
229
+
230
+ private predicate isPotentialModuleFile ( File file , string name ) {
231
+ legalShortName ( name ) and
232
+ name = file .getStem ( ) and
233
+ file .getExtension ( ) = [ "py" , "pyc" , "so" , "pyd" ] and
234
+ // it has to be imported in this folder
235
+ name =
236
+ any ( ImportExpr i | i .getLocation ( ) .getFile ( ) .getParent ( ) = file .getParent ( ) )
237
+ .getName ( )
238
+ .regexpReplaceAll ( "\\..*" , "" ) and
239
+ name != ""
240
+ }
241
+
242
+ // See https://peps.python.org/pep-0420/#specification
243
+ private predicate isNameSpacePackage ( Folder f , string name ) {
244
+ legalShortName ( name ) and
245
+ name = f .getStem ( ) and
246
+ not isRegularPackage ( f , name ) and
247
+ // it has to be imported in this folder
248
+ name =
249
+ any ( ImportExpr i | i .getLocation ( ) .getFile ( ) .getParent ( ) = f )
250
+ .getName ( )
251
+ .regexpReplaceAll ( "\\..*" , "" ) and
252
+ name != "" and
253
+ // no siblibling regular package
254
+ // no sibling module
255
+ not exists ( Folder sibling | sibling .getParent ( ) = f .getParent ( ) |
256
+ isRegularPackage ( sibling .getFolder ( name ) , name )
257
+ or
258
+ isPotentialModuleFile ( sibling .getAFile ( ) , name )
259
+ )
260
+ }
261
+
262
+ private predicate isPackage ( Folder f , string name ) {
263
+ isRegularPackage ( f , name )
264
+ or
265
+ isNameSpacePackage ( f , name )
266
+ }
267
+
268
+ private predicate isModuleFile ( File file , string name ) {
269
+ isPotentialModuleFile ( file , name ) and
270
+ not isPackage ( file .getParent ( ) , _)
271
+ }
272
+
273
+ private predicate isOutermostPackage ( Folder f , string name ) {
274
+ isPackage ( f , name ) and
275
+ not isPackage ( f .getParent ( ) , _)
276
+ }
277
+
239
278
cached
240
- string moduleNameFromFile ( Container file ) {
279
+ string moduleNameFromFile ( Container c ) {
280
+ // package
281
+ isOutermostPackage ( c , result )
282
+ or
283
+ // module
284
+ isModuleFile ( c , result )
285
+ or
241
286
Stages:: AST:: ref ( ) and
242
287
exists ( string basename |
243
- basename = moduleNameFromBase ( file ) and
288
+ basename = moduleNameFromBase ( c ) and
244
289
legalShortName ( basename )
245
290
|
246
- result = moduleNameFromFile ( file .getParent ( ) ) + "." + basename
291
+ // recursive case
292
+ result = moduleNameFromFile ( c .getParent ( ) ) + "." + basename
247
293
or
248
294
// If `file` is a transitive import of a file that's executed directly, we allow references
249
295
// to it by its `basename`.
250
- transitively_imported_from_entry_point ( file ) and
296
+ transitively_imported_from_entry_point ( c ) and
251
297
result = basename
252
298
)
253
299
or
254
- isPotentialSourcePackage ( file ) and
255
- result = file .getStem ( ) and
256
- (
257
- not isPotentialSourcePackage ( file .getParent ( ) ) or
258
- not legalShortName ( file .getParent ( ) .getBaseName ( ) )
259
- )
260
- or
261
- result = file .getStem ( ) and file .getParent ( ) = file .getImportRoot ( )
300
+ //
301
+ // standard library
302
+ result = c .getStem ( ) and c .getParent ( ) = c .getImportRoot ( )
262
303
or
263
- result = file .getStem ( ) and isStubRoot ( file .getParent ( ) )
304
+ result = c .getStem ( ) and isStubRoot ( c .getParent ( ) )
264
305
}
265
306
266
307
private predicate isStubRoot ( Folder f ) {
0 commit comments