Autoimport
Autoimport missing python libraries.
Throughout the development of a python program you continuously need to manage the python import statements either because you need one new object or because you no longer need it. This means that you need to stop writing whatever you were writing, go to the top of the file, create or remove the import statement and then resume coding.
This workflow break is annoying and almost always unnecessary. autoimport
solves this problem if you execute it whenever you have an import error, for example by configuring your editor to run it when saving the file.
Installing¶
pip install autoimport
Usage¶
Imagine we've got the following source code:
import requests
def hello(names: Tuple[str]) -> None:
for name in names:
print(f"Hi {name}!")
os.getcwd()
It has the following import errors:
requests
is imported but unused.os
andTuple
are needed but not imported.
After running autoimport
the resulting source code will be:
import os
from typing import Tuple
def hello(names: Tuple[str]) -> None:
for name in names:
print(f"Hi {name}!")
os.getcwd()
autoimport
can be used both as command line tool and as a library.
It can be parsed either an array of files and/or a directory.
A parsed directory will have autoimport
be executed on all recursively found python files in said directory.
- As a command line tool:
$: autoimport file.py
$: autoimport dir/
- As a library:
from autoimport import fix_files
fix_files(["file.py", "dir/"])
Warning: autoimport
will add all dependencies at the top of the file, we suggest using isort and black afterwards to clean the file.
Features¶
Add missing imports¶
autoimport
matches each of the missing import statements against the following objects:
-
The modules referenced in
PYTHONPATH
. -
The
typing
library objects. -
The common statements. Where some of the common statements are:
-
BeautifulSoup
->from bs4 import BeautifulSoup
call
->from unittest.mock import call
CaptureFixture
->from _pytest.capture import CaptureFixture
CliRunner
->from click.testing import CliRunner
copyfile
->from shutil import copyfile
dedent
->from textwrap import dedent
LocalPath
->from py._path.local import LocalPath
LogCaptureFixture
->from _pytest.logging import LogCaptureFixture
Mock
->from unittest.mock import Mock
patch
->from unittest.mock import patch
StringIO
->from io import StringIO
-
YAMLError
->from yaml import YAMLError
-
The objects of the Python project you are developing, assuming you are executing the program in a directory of the project and you can import it.
Warning: It may not work if you use pip install -e .
. Given that you execute autoimport
inside a virtualenv where the package is installed with pip install -e .
, when there is an import error in a file that is indexed in the package, autoimport
won't be able to read the package contents as the import
statement will fail. So it's a good idea to run autoimport from a virtualenv that has a stable version of the package we are developing.
Remove unused import statements¶
If an object is imported but unused, autoimport
will remove the import statement.
This can be problematic when run in __init__.py
files, which often contain "unused" imports. To tell autoimport
to not run on these files, you can use the --ignore-init-modules
flag, which will filter away any passed __init__.py
files before processing.
There may be import statements that are being used dynamically, to autoimport it would look like those are not being used but actually they may have some usages.
In such cases where you want to retain the unused imports across any file, you can use the --keep-unused-imports
flag, which will prevent autoimport
from removing any import statements.
Note: If there are not many cases where you intend to keep the unused imports, prefer placing #noqa: autoimport
on the concerned import line/s, over using the --keep-unused-imports
flag.
Moving the imports to the top¶
There are going to be import cases that may not work, if you find one, please open an issue.
While we fix it you can write the import statement wherever you are in the file and the next time you run autoimport
it will get moved to the top.
If you don't want a specific line to go to the top, add the # noqa: autoimport
or # fmt: skip
at the end. For example:
a = 1
from os import getcwd # noqa: autoimport
getcwd()
Configuration¶
autoimport
uses the maison
library to discover and read your project-local pyproject.toml
file (if it exists). This file can be used to configure autoimport
's behavior: the tool.autoimport.common_statements
table in that file can be used to define a custom set of "common statements", overriding the default set of common statements mentioned above. For example:
# pyproject.toml
[tool.autoimport.common_statements]
"np" = "import numpy as np"
"FooBar" = "from baz_qux import FooBar"
It is also possible to specify a different path for this config file:
$: autoimport --config-file ~/.autoimport.toml file.py
If using the --config-file
flag to specify a file that is named something other than pyproject.toml
, the autoimport settings should not be nested under toplevel tool.autoimport
keys.
# .autoimport.toml
[common_statements]
"np" = "import numpy as np"
"FooBar" = "from baz_qux import FooBar"
Furthermore, autoimport
supports the use of a global configuration file, located at autoimport/config.toml
under the xdg config home folder. For most users, this means that the file ~/.config/autoimport/config.toml
, if it exists, will be loaded and used as configuration for autoimport
. As before, do not write tool.autoimport
at the toplevel; just specify your global autoimport
settings directly.
The settings defined in the local pyproject.toml
file (if found) or in the file specified by the --config-file
flag (if given) will override the settings defined in the global autoimport/config.toml
file.
Disabling Move To Top¶
While discouraged in favor of proper refactoring to eliminate cyclical dependencies, it is possible to disable autoimport from moving import statements to the tops of the files.
To do so, set disable_move_to_top
to true
. Here is how that might look in a pyproject.toml
configuration file.
[tool.autoimport]
disable_move_to_top = true
References¶
As most open sourced programs, autoimport
is standing on the shoulders of giants, namely:
- autoflake: Inspiration of
autoimport
. Also used their code to interact with - pyflakes.
- Click: Used to create the command line interface.
- Pytest: Testing framework, enhanced by the awesome pytest-cases library that made the parametrization of the tests a lovely experience.
- Mypy: Python static type checker.
- Flakeheaven: Python linter with lots of checks.
- Black: Python formatter to keep a nice style without effort.
- Autoimport: Python formatter to automatically fix wrong import statements.
- isort: Python formatter to order the import statements.
- PDM: Command line tool to manage the dependencies.
- Mkdocs: To build this documentation site, with the
- Material theme.
- Safety: To check the installed dependencies for known security vulnerabilities.
- Bandit: To finds common security issues in Python code.
- Yamlfix: YAML fixer.
Alternatives¶
If you like the idea but not how we solved the problem, take a look at this other solutions:
Contributing¶
For guidance on setting up a development environment, and how to make a contribution to autoimport, see Contributing to autoimport.