コンテンツにスキップ

concrete-instantiation-dependency

Category: Dependency Injection
Severity: Warning
Triggered by: pyscn analyze, pyscn check --select di

What it does

Flags a class that constructs a concrete collaborator inside __init__ (e.g. self.repo = SqlUserRepository()) rather than receiving it as a parameter.

Why is this a problem?

When a class builds its own collaborators, it also owns their configuration, their lifetime, and their transitive dependencies. OrderService() suddenly requires a database connection string, an HTTP client, and credentials — all reached for implicitly — because SqlUserRepository() and StripeGateway() do.

Tests feel this first. There is no seam to swap in a fake: every test has to either spin up the real collaborator or monkey-patch the class being constructed. Integration tests and unit tests blur together, and the test suite slows down.

Passing the collaborator in makes the dependency explicit, keeps the class focused on its own logic, and lets different call sites wire different implementations — a real repository in production, an in-memory one in tests.

Example

class OrderService:
    def __init__(self):
        self.repo = SqlOrderRepository(DATABASE_URL)
        self.payments = StripeGateway(api_key=STRIPE_KEY)

    def place(self, order):
        self.repo.save(order)
        self.payments.charge(order)

Use instead

Receive the collaborators via __init__ and construct them once at the composition root.

class OrderService:
    def __init__(self, repo, payments):
        self.repo = repo
        self.payments = payments

    def place(self, order):
        self.repo.save(order)
        self.payments.charge(order)

Options

Option Default Description
di.enabled false Must be true for analyze to run DI rules.
di.min_severity "warning" Raise to "error" to suppress this rule.

References