Skip to content

require-public-dependency-contract

Reuse an existing substitutable contract instead of its concrete implementation annotation.

Why

A concrete dependency annotation obstructs substitution even when an existing public contract already has multiple implementations.

Fix

Annotate the dependency with the existing public contract; do not create a new interface.

Examples

Before — flagged Use the existing substitutable publisher contract
app/__init__.py
# package
app/consumer.py
from app.publisher import Publisher, HttpPublisher
class Consumer:
def __init__(self, publisher: HttpPublisher) -> None:
self.publisher = publisher
def run(self) -> None:
self.publisher.publish()
app/publisher.py
from abc import ABC, abstractmethod
class Publisher(ABC):
@abstractmethod
def publish(self) -> None: ...
class HttpPublisher(Publisher):
def publish(self) -> None: ...
class QueuePublisher(Publisher):
def publish(self) -> None: ...
After — preferred The consumer already uses the existing contract
app/__init__.py
# package
app/consumer.py
from app.publisher import Publisher, HttpPublisher
class Consumer:
def __init__(self, publisher: Publisher) -> None:
self.publisher = publisher
def run(self) -> None:
self.publisher.publish()
app/publisher.py
from abc import ABC, abstractmethod
class Publisher(ABC):
@abstractmethod
def publish(self) -> None: ...
class HttpPublisher(Publisher):
def publish(self) -> None: ...
class QueuePublisher(Publisher):
def publish(self) -> None: ...