implement-dependency-injection
Provides comprehensive guide for adding services to dependency injection Container using dependency-injector library patterns including Singleton vs Factory vs Dependency providers, override patterns for testing, and circular dependency detection. Use when creating new service, adding dependency to Container, debugging circular dependency errors, or wiring components for injection.
What this skill does
Works with container.py and container_factory.py files.
# Implement Dependency Injection
## Purpose
Guides proper integration of services into the dependency injection Container using the `dependency-injector` library. Ensures correct provider selection, prevents circular dependencies, and enables testability through override patterns.
## When to Use
Use this skill when:
- **Creating new service** - Adding a service that needs dependencies
- **Adding dependency to Container** - Wiring components for injection
- **Debugging circular dependency errors** - Resolving dependency cycles
- **Wiring components for injection** - Setting up proper dependency flow
- **Setting up test overrides** - Mocking dependencies in tests
**Trigger phrases:**
- "Add X to the dependency container"
- "Wire Y service with dependencies"
- "Fix circular dependency error"
- "Override dependency for testing"
## Quick Start
**Adding a simple service to Container:**
```python
# In container.py
my_service = providers.Singleton(
MyService,
settings=settings,
dependency1=some_dependency,
)
```
## Table of Contents
### Core Sections
- [Purpose](#purpose) - Single-sentence skill objective
- [Quick Start](#quick-start) - Immediate, copy-paste ready example
- [Instructions](#instructions) - Complete implementation guide
- [Step 1: Determine Provider Type](#step-1-determine-provider-type) - Singleton vs Factory vs Dependency
- [Step 2: Add Service to Container](#step-2-add-service-to-container) - Container.py integration
- [Step 3: Handle Special Cases](#step-3-handle-special-cases) - Factory functions, config extraction, circular dependencies
- [Step 4: Override for Testing](#step-4-override-for-testing) - Test fixture patterns
- [Step 5: Initialize in Factory](#step-5-initialize-in-factory) - MCP server initialization
- [Examples](#examples) - Concrete, working implementations
- [Example 1: Add Repository (Singleton)](#example-1-add-repository-singleton)
- [Example 2: Add Command Handler (Factory)](#example-2-add-command-handler-factory)
- [Example 3: Override for Testing](#example-3-override-for-testing)
- [Requirements](#requirements) - Dependencies, files, quality checks
- [Common Pitfalls](#common-pitfalls) - Troubleshooting guide
### Supporting Resources
- [references/provider-reference.md](./references/provider-reference.md) - Complete dependency-injector API reference
- [references/circular-dependency-guide.md](./references/circular-dependency-guide.md) - Circular dependency resolution strategies
- [templates/service-template.py](./templates/service-template.py) - Service class template with DI
### Utility Scripts
- [Detect Circular Dependencies](./scripts/detect_circular_deps.py) - Detect circular dependencies in DI container
- [Generate Provider](./scripts/generate_provider.py) - Auto-generate provider code for container
- [Validate DI Patterns](./scripts/validate_di_patterns.py) - Validate dependency injection patterns in codebase
## Instructions
### Step 1: Determine Provider Type
Choose the appropriate provider based on lifecycle requirements:
**Use `providers.Singleton`:**
- Stateful services (repositories, caches)
- Expensive initialization (database connections, embedding models)
- Shared state needed across requests
- Most application/infrastructure services
**Use `providers.Factory`:**
- Request handlers (command/query handlers)
- Stateless operations
- New instance needed per invocation
- Short-lived objects
**Use `providers.Dependency`:**
- External dependencies provided at runtime
- Configuration objects (Settings)
- Infrastructure connections (neo4j_driver)
- Services from outside the container
### Step 2: Add Service to Container
**Location:** `/Users/dawiddutoit/projects/play/project-watch-mcp/src/project_watch_mcp/interfaces/mcp/container.py`
Add provider in the appropriate layer section:
```python
class Container(containers.DeclarativeContainer):
# Configuration
settings = providers.Dependency(instance_of=Settings)
# Infrastructure Layer - Repositories
my_repository = providers.Singleton(
MyRepository,
driver=neo4j_driver,
settings=settings,
)
# Application Layer - Services
my_service = providers.Singleton(
MyService,
settings=settings,
repository=my_repository,
)
# Application Layer - Command Handlers
my_handler = providers.Factory(
MyHandler,
service=my_service,
)
```
**Ordering matters:** Define dependencies before dependents to avoid circular references.
### Step 3: Handle Special Cases
**Factory Functions (for complex initialization):**
```python
def create_extractor_registry(python_ext):
"""Factory function to create and configure extractor registry."""
registry = ExtractorRegistry()
registry.register(python_ext)
return registry
extractor_registry = providers.Singleton(
create_extractor_registry,
python_ext=python_extractor,
)
```
**Extracting Config Values:**
```python
smart_chunking_service = providers.Singleton(
SmartChunkingService,
boundary_adjustment_lines=providers.Factory(
lambda s: s.chunking.boundary_adjustment_lines,
s=settings,
),
settings=settings,
)
```
**Avoiding Circular Dependencies:**
- Order providers: dependencies before dependents
- Use lazy evaluation with `providers.Factory`
- Consider extracting shared dependencies to separate provider
- See `references/circular-dependency-guide.md` for resolution strategies
### Step 4: Override for Testing
**In test files (conftest.py or test methods):**
```python
@pytest.fixture
def container(real_settings, mock_driver):
"""Create container with test overrides."""
container = Container()
# Override dependencies
container.settings.override(real_settings)
container.neo4j_driver.override(mock_driver)
return container
def test_service(container):
"""Test service from container."""
service = container.my_service()
assert service.settings is not None
```
### Step 5: Initialize in Factory
**For MCP server initialization:**
Update `/Users/dawiddutoit/projects/play/project-watch-mcp/src/project_watch_mcp/interfaces/mcp/container_factory.py`:
```python
def initialize_container_and_services(
repository_monitor: RepositoryMonitor,
neo4j_rag: Neo4jRAG,
settings: Settings,
) -> Container:
"""Initialize container with runtime dependencies."""
container = Container()
# Override external dependencies
container.settings.override(settings)
container.neo4j_driver.override(neo4j_rag.neo4j_database.driver)
container.repository_monitor.override(repository_monitor)
# Initialize services with side effects
_ = container.my_service()
return container
```
## Examples
### Example 1: Add Repository (Singleton)
```python
# In container.py - Infrastructure Layer section
file_metadata_repository = providers.Singleton(
FileMetadataRepository,
driver=neo4j_driver,
settings=settings,
)
```
**Why Singleton:** Repositories are stateful, manage connections, expensive to create.
### Example 2: Add Command Handler (Factory)
```python
# In container.py - Application Layer section
process_file_handler = providers.Factory(
ProcessFileHandler,
repository=file_metadata_repository,
chunking_service=chunking_service,
settings=settings,
)
```
**Why Factory:** Handlers are invoked per request, should be stateless.
### Example 3: Override for Testing
```python
# In tests/integration/mymodule/conftest.py
@pytest.fixture
def container(real_settings):
container = Container()
container.settings.override(real_settings)
# Override with mock driver
mock_driver = AsyncMock()
container.neo4j_driver.override(mock_driver)
return container
def test_handler_uses_repository(container):
handler = container.process_file_handler()
# handler now uses mocked driver through repositoryRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.