Skip to content

Autoimport

Actions Status Actions Status Coverage Status

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 and Tuple 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.