Package: removestar
removestarTool to automatically replaceimport *imports in Python files with explicit importsInstallationInstallremovestarglobally to use it through CLI usingpypi-pipinstallremovestarorconda-condainstall-cconda-forgeremovestaror addremovestarin.pre-commit-config.yaml--repo:https://github.com/asmeurer/removestarrev:v1.4hooks:-id:removestarargs:[-i]# See docs for all args (-i edits file in-place)additional_dependencies:# The libraries or packages your code imports-...# Should be . if running inside a library (to install the library itself in the environment)Usagepre-commit hookOnceremovestaris added in.pre-commit-config.yaml, executing the following
will always run it (and other pre-commits) before every commit -pre-commitinstallOptionally, the pre-commits (includingremovestar) can be manually triggered for
all the files using -pre-commitrun--all-filesCLI# scripts$removestarfile.py# Shows diff but does not edit file.py$removestar-ifile.py# Edits file.py in-place$removestar-imodule/# Modifies every Python file in module/ recursively# notebooks$removestarfile.ipynb# Shows diff but does not edit file.ipynb$removestar-ifile.ipynb# Edits file.ipynb in-placeWhy isimport *so bad?Doingfrom module import *is generally frowned upon in Python. It is
considered acceptable when working interactively at apythonprompt, or in__init__.pyfiles (removestar skips__init__.pyfiles by default).Some reasons whyimport *is bad:It hides which names are actually imported.It is difficult both for human readers and static analyzers such as
pyflakes to tell where a given name comes from whenimport *is used. For
example, pyflakes cannot detect unused names (for instance, from typos) in
the presence ofimport *.If there are multipleimport *statements, it may not be clear which names
come from which module. In some cases, both modules may have a given name,
but only the second import will end up being used. This can break people's
intuition that the order of imports in a Python file generally does not
matter.import *often imports more names than you would expect. Unless the module
you import defines__all__or carefullydels unused names at the module
level,import *will import every public (doesn't start with an
underscore) name defined in the module file. This can often include things
like standard library imports or loop variables defined at the top-level of
the file. For imports from modules (from__init__.py),from module import *will include every submodule defined in that module. Using__all__in
modules and__init__.pyfiles is also good practice, as these things are
also often confusing even for interactive use whereimport *is
acceptable.In Python 3,import *is syntactically not allowed inside of a function.Here are some official Python references stating not to useimport *in
files:The official Python
FAQ:In general, don’t usefrom modulename import *. Doing so clutters the
importer’s namespace, and makes it much harder for linters to detect
undefined names.PEP 8(the official
Python style guide):Wildcard imports (from <module> import *) should be avoided, as they
make it unclear which names are present in the namespace, confusing both
readers and many automated tools.Unfortunately, if you come across a file in the wild that usesimport *, it
can be hard to fix it, because you need to find every name in the file that is
imported from the*. Removestar makes this easy by finding which names come
from*imports and replacing the import lines in the file automatically.One exception whereimport *can be bneficial:
At the early stages of code development, a definite set of required
functions can be difficult to determine. In such a context, wildcard imports could be
beneficial by avoiding constantly curating the set of required functions. For example,
at the development stage usage offrom os.path import *can save time from curating
required functions. Post-development, the wld card imports could be determined usingremovestar. Having said that, because of the multiple said reasons, wildcard imports
should be avoided.ExampleSuppose you have a modulemymodlikemymod/|__init__.py|a.py|b.pyWith# mymod/a.pyfrom.bimport*deffunc(x):returnx+y# mymod/b.pyx=1y=2Thenremovestarworks like:$removestarmymod/

---original/mymod/a.py
+++fixed/mymod/a.py
@@-1,5+1,5@@# mymod/a.py-from.bimport*
+from.bimportydeffunc(x):returnx+yThis does not edita.pyby default. The-iflag causes it to edita.pyin-place:$removestar-imymod/
$catmymod/a.py# mymod/a.pyfrom.bimporty

deffunc(x):returnx+yCommand line options$removestar--help
usage:removestar[-h][-i][--version][--no-skip-init][--no-dynamic-importing][-v][-q][--max-line-lengthMAX_LINE_LENGTH]PATH[PATH...]Tooltoautomaticallyreplace"import *"importswithexplicitimports

Requirespyflakes.

Usage:

$removestarfile.py# Shows diff but does not edit file.py$removestar-ifile.py# Edits file.py in-place$removestar-imodule/# Modifies every Python file in module/ recursivelypositionalarguments:PATHFilesordirectoriestofix

optionalarguments:-h,--helpshowthishelpmessageandexit-i,--in-placeEditthefilesin-place.(default:False)--versionShowremovestarversionnumberandexit.--no-skip-initDon't skip __init__.py files (they are skipped bydefault) (default: True)--no-dynamic-importingDon'tdynamicallyimportmodulestodeterminethelistofnames.Thisisrequiredforstarimportsfromexternalmodulesandmodulesinthestandardlibrary.(default:True)-v,--verbosePrintinformationabouteveryimportednamethatisreplaced.(default:False)-q,--quietDon'tprintanywarningmessages.(default:False)--max-line-lengthMAX_LINE_LENGTHThemaximumlinelengthforreplacedimportsbeforetheyarewrapped.Setto0todisablelinewrapping.(default:100)Whitelisting star importsremovestardoes not replace star import lines that are marked withFlake8noqacommentsthat permit star imports (F401orF403).For example, the star imports in this module would be kept:fromosimport*# noqa: F401from.bimport*# noqadeffunc(x):returnx+yCurrent limitationsAssumes only names in the current file are used by star imports (e.g., it
won't work to replace star imports in__init__.py).For files within the same module, removestar determines missing imported names
statically. For external library imports, including imports of standard
library modules, it dynamically imports the module to determine the names.
This can be disabled with the--no-dynamic-importingflag.ContributingSee theissue tracker. Pull
requests are welcome.ChangelogSee theCHANGELOGfile.LicenseMIT