Skip to main content

Static code analysis for search of dependencies injection

Project description

Dependency Injection Linter

A static code analysis tool that detects dependency injection anti-patterns in Python projects. This linter helps enforce clean architecture principles by identifying direct instantiation or usage of project-specific dependencies within your code.

What is Dependency Injection?

Dependency Injection is a design pattern where a class or function receives its dependencies from external sources rather than creating them internally. This pattern promotes:

  • Loose coupling between components
  • Better testability through easier mocking of dependencies
  • Improved maintainability by centralizing dependency management
  • Enhanced flexibility for swapping implementations

What This Linter Detects

This linter identifies cases where project-specific dependencies are directly created or used within functions or methods, rather than being injected as parameters. It helps enforce the principle that dependencies should be passed in, not created internally.

Examples of Dependency Injection Issues

# BAD: Direct instantiation of project dependencies
from project.user.repo import UserRepository

def process_data():
    repository = UserRepository()  # DI001: Dependency injection
    data = repository.get_all()
    return data

# BAD: Direct usage of project module functions
from project.notifications import send_email

def send_notification():
    send_email("user@example.com", "Hello")  # DI001: Dependency injection

# BAD: Using context managers from project modules
from project.db import context_manager

def backup_data():
    with context_manager():  # DI001: Dependency injection
        # do something
        pass

See more examples in my_module.py

Correct Approaches

# GOOD: Dependencies injected as parameters
def process_data(repository):
    data = repository.get_all()
    return data

# GOOD: Dependencies passed as arguments
def send_notification(email_sender):
    email_sender("user@example.com", "Hello")

# GOOD: Context managers passed as parameters
def backup_data(context_manager):
    with context_manager():
        # do something
        pass

Installation

pip install di-linter

Usage

As a standalone tool

  1. Run the linter specifying the project directory:
di-linter path/to/project
  1. Run the linter using a configuration file:
di-linter --config-path di.toml

As a flake8 plugin

flake8 --select=DI path/to/your/project

Configuration

Standalone tool configuration

The configuration file di.toml is optional. If not provided, the linter will work with default settings.

# Required: The root directory of your project
project-root = "project"

# Optional: Objects to exclude from dependency injection checks
exclude-objects = ["Settings", "DIContainer"]

# Optional: Modules to exclude from dependency injection checks
exclude-modules = ["endpoints.py"]

Configuration File Location

The linter looks for the configuration file in the following locations:

  1. The current working directory (./di.toml)
  2. The parent directory of the project root

You can also specify a custom path to the configuration file using the --config-path option:

di-linter path/to/project --config-path /path/to/custom/di.toml

Project Root Detection

The project root is automatically detected by looking for marker files such as:

  • setup.py
  • setup.cfg
  • pyproject.toml
  • requirements.txt

Or by finding the directory where __init__.py is no longer present in the parent directory.

flake8 plugin configuration

The configuration file di.toml is optional for the flake8 plugin as well. If not provided, the plugin will work with default settings and follow the same configuration file search logic as the standalone tool.

Add the following to your flake8 configuration file (e.g., .flake8, setup.cfg, or tox.ini):

[flake8]
select = DI
di-exclude-objects = Settings,DIContainer
di-exclude-modules = endpoints.py
di-config = path/to/di.toml  # Optional: custom path to configuration file

You can also specify these options on the command line:

flake8 --select=DI --di-exclude-objects=Settings,DIContainer --di-exclude-modules=endpoints.py --di-config=path/to/di.toml path/to/your/project

The --di-config option allows you to specify a custom path to the configuration file, which is useful when you want to use a configuration file that's not in one of the default locations.

Skipping Specific Lines

You can skip specific lines by adding a comment with # di: skip:

def myfunc():
    repository = UserRepository()  # di: skip

Error Codes

Code Description
DI001 Dependency injection: Direct usage of project dependencies

Output Examples

Standalone Tool Output

Analyzing: /path/to/project
Project name: project
Exclude objects: []
Exclude modules: []
/path/to/project/module.py:10: Dependency injection: UserRepository()
/path/to/project/module.py:15: Dependency injection: with db_transaction():

flake8 Plugin Output

/path/to/project/module.py:10:5: DI001 Dependency injection: UserRepository()
/path/to/project/module.py:15:10: DI001 Dependency injection: with db_transaction():

Visual Example

img.png

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

di_linter-1.0.3.tar.gz (732.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

di_linter-1.0.3-py3-none-any.whl (10.6 kB view details)

Uploaded Python 3

File details

Details for the file di_linter-1.0.3.tar.gz.

File metadata

  • Download URL: di_linter-1.0.3.tar.gz
  • Upload date:
  • Size: 732.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.3

File hashes

Hashes for di_linter-1.0.3.tar.gz
Algorithm Hash digest
SHA256 be0acb34ef83d4b06588685759032f1ce6a106ac96ed8c4793a2ad0d0118a0ef
MD5 f1dbe9b69353ae8473f0a650dbb65395
BLAKE2b-256 b0fe1772716e6b93d1aa19f657ac83f8c7570234846c45c7c7681f3199af0742

See more details on using hashes here.

File details

Details for the file di_linter-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: di_linter-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 10.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.6.3

File hashes

Hashes for di_linter-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 0f4d0bd01e69e2a9523e67c11aad89ec4252a6ff134d3f585934b5894ba5b6d7
MD5 ad73ac6efb13227678be5760b1cef5a4
BLAKE2b-256 adb6857087e1ac5a215c85d5ccde8c593ccc56ed63f8a263abb684f97381a98c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page