@@ -294,7 +294,8 @@ def break_up_import(line):
294294def filter_code (source , additional_imports = None ,
295295 expand_star_imports = False ,
296296 remove_all_unused_imports = False ,
297- remove_unused_variables = False ):
297+ remove_unused_variables = False ,
298+ populate_all = False ):
298299 """Yield code with unused imports removed."""
299300 imports = SAFE_IMPORTS
300301 if additional_imports :
@@ -335,6 +336,10 @@ def filter_code(source, additional_imports=None,
335336 else :
336337 marked_variable_line_numbers = frozenset ()
337338
339+ if populate_all :
340+ marked_import_line_numbers = frozenset ()
341+ source = populate_all_with_modules (source , marked_unused_module )
342+
338343 sio = io .StringIO (source )
339344 previous_line = ''
340345 for line_number , line in enumerate (sio .readlines (), start = 1 ):
@@ -478,6 +483,43 @@ def filter_useless_pass(source):
478483 yield line
479484
480485
486+ def populate_all_with_modules (source , marked_unused_module ):
487+ all_syntax = re .search ('^__all__(.)+\]' , source , flags = re .MULTILINE )
488+ if all_syntax :
489+ # If there are existing `__all__`, parse it and append to it
490+ insert_position = all_syntax .span ()[0 ]
491+ end_position = all_syntax .span ()[1 ]
492+ all_modules = all_syntax .group ().split ('=' )[1 ].strip ()
493+ all_modules = ast .literal_eval (all_modules )
494+ else :
495+ # If no existing `__all__`, always append in EOF
496+ insert_position = len (source )
497+ end_position = - 1
498+ all_modules = []
499+
500+ for modules in marked_unused_module .values ():
501+ # Get the imported name, `a.b.Foo` -> Foo
502+ all_modules += [get_imported_name (name ) for name in modules ]
503+
504+ new_all_syntax = '__all__ = ' + str (all_modules )
505+ source = source [:insert_position ] + new_all_syntax + source [end_position :]
506+ return source
507+
508+
509+ def get_imported_name (module ):
510+ """
511+ Return only imported name from pyflakes full module path
512+
513+ Example:
514+ - `a.b.Foo` -> `Foo`
515+ - `a as b` -> b
516+ """
517+ if '.' in module :
518+ return module .split ('.' )[- 1 ]
519+ elif ' as ' in module :
520+ return module .split (' as ' )[- 1 ]
521+ return module
522+
481523def get_indentation (line ):
482524 """Return leading whitespace."""
483525 if line .strip ():
@@ -497,7 +539,8 @@ def get_line_ending(line):
497539
498540
499541def fix_code (source , additional_imports = None , expand_star_imports = False ,
500- remove_all_unused_imports = False , remove_unused_variables = False ):
542+ remove_all_unused_imports = False , remove_unused_variables = False ,
543+ populate_all = False ):
501544 """Return code with all filtering run on it."""
502545 if not source :
503546 return source
@@ -515,9 +558,10 @@ def fix_code(source, additional_imports=None, expand_star_imports=False,
515558 additional_imports = additional_imports ,
516559 expand_star_imports = expand_star_imports ,
517560 remove_all_unused_imports = remove_all_unused_imports ,
518- remove_unused_variables = remove_unused_variables ))))
561+ remove_unused_variables = remove_unused_variables ,
562+ populate_all = populate_all ))))
519563
520- if filtered_source == source :
564+ if filtered_source == source or populate_all :
521565 break
522566 source = filtered_source
523567
@@ -537,7 +581,9 @@ def fix_file(filename, args, standard_out):
537581 additional_imports = args .imports .split (',' ) if args .imports else None ,
538582 expand_star_imports = args .expand_star_imports ,
539583 remove_all_unused_imports = args .remove_all_unused_imports ,
540- remove_unused_variables = args .remove_unused_variables )
584+ remove_unused_variables = args .remove_unused_variables ,
585+ populate_all = args .populate_all ,
586+ )
541587
542588 if original_source != filtered_source :
543589 if args .in_place :
@@ -692,6 +738,9 @@ def _main(argv, standard_out, standard_error):
692738 'one star import in the file; this is skipped if '
693739 'there are any uses of `__all__` or `del` in the '
694740 'file' )
741+ parser .add_argument ('--populate-all' , action = 'store_true' ,
742+ help = 'populate `__all__` with unused import found in '
743+ 'the code.' )
695744 parser .add_argument ('--remove-all-unused-imports' , action = 'store_true' ,
696745 help = 'remove all unused imports (not just those from '
697746 'the standard library)' )
0 commit comments