Skip to main content
mySpellChecker uses a lightweight dependency injection (DI) system for managing component lifecycles and dependencies. This enables loose coupling, easier testing, and flexible configuration.

Overview

The DI system consists of:
  • ServiceContainer: Central registry for services
  • Factory Functions: Create components with dependencies
  • ComponentFactory: High-level factory for spell checker components

ServiceContainer

The ServiceContainer manages component lifecycle through factory functions:
from myspellchecker.core.di.container import ServiceContainer
from myspellchecker.core.config import SpellCheckerConfig

config = SpellCheckerConfig()
container = ServiceContainer(config)

Registering Services

Register factory functions that create services:
def create_provider(container):
    """Factory function for provider."""
    config = container.get_config()
    return SQLiteProvider(database_path=config.provider_config.database_path)

# Register as singleton (default)
container.register_factory("provider", create_provider, singleton=True)

# Register as transient (new instance each time)
container.register_factory("temp_service", create_temp, singleton=False)

Retrieving Services

Services are created lazily on first access:
# First call creates the instance
provider = container.get("provider")

# Subsequent calls return cached instance (for singletons)
provider2 = container.get("provider")
assert provider is provider2  # Same instance

Available Services

The default container provides these services:
Service NameTypeDescription
providerDictionaryProviderDictionary storage backend
segmenterSegmenterText segmentation
phonetic_hasherPhoneticHasherPhonetic matching (optional)
rankerSuggestionRankerSuggestion ranking
symspellSymSpellSymSpell algorithm
context_checkerNgramContextCheckerN-gram checking (optional)
syllable_validatorSyllableValidatorSyllable validation
word_validatorWordValidatorWord validation
context_validatorContextValidatorContext validation

Thread Safety

Singleton creation is thread-safe using double-checked locking:
# Safe to call from multiple threads
from concurrent.futures import ThreadPoolExecutor

with ThreadPoolExecutor(max_workers=4) as executor:
    futures = [executor.submit(container.get, "provider") for _ in range(10)]
    providers = [f.result() for f in futures]

# All return the same instance
assert all(p is providers[0] for p in providers)

Container Operations

# Check if service is registered
if container.has_service("provider"):
    provider = container.get("provider")

# List all registered services
services = container.list_services()
print(services)  # ['context_checker', 'phonetic_hasher', 'provider', ...]

# Clear cached instances (forces recreation)
container.clear_cache()

Component Factories

Individual component factories create specific services:

ProviderFactory

ProviderFactory is a type alias for Callable[[ServiceContainer], DictionaryProvider]. Use create_provider_factory() to get the factory function:
from myspellchecker.core.factories.provider_factory import create_provider_factory

factory_fn = create_provider_factory()
container.register_factory("provider", factory_fn)
provider = container.get("provider")

SymSpellFactory

SymSpellFactory is a type alias for Callable[[ServiceContainer], SymSpell]. Use create_symspell_factory() to get the factory function:
from myspellchecker.core.factories.symspell_factory import create_symspell_factory

factory_fn = create_symspell_factory()
container.register_factory("symspell", factory_fn)
symspell = container.get("symspell")

ValidatorsFactory

ValidatorFactory is a type alias for Callable[[ServiceContainer], Validator]. create_validators_factory() returns a dict of named factory functions:
from myspellchecker.core.factories.validators_factory import create_validators_factory

validator_factories = create_validators_factory()
# Keys are "syllable", "word", "context"
for name, factory_fn in validator_factories.items():
    container.register_factory(f"{name}_validator", factory_fn)

syllable_validator = container.get("syllable_validator")
word_validator = container.get("word_validator")
context_validator = container.get("context_validator")

SegmenterFactory

SegmenterFactory is a type alias for Callable[[ServiceContainer], Segmenter]. Use create_segmenter_factory() to get the factory function:
from myspellchecker.core.factories.segmenter_factory import create_segmenter_factory

factory_fn = create_segmenter_factory()
container.register_factory("segmenter", factory_fn)
segmenter = container.get("segmenter")

RankerFactory

The ranker factory uses create_base_ranker() which takes a RankerConfig directly (not the container pattern):
from myspellchecker.core.factories.ranker_factory import create_base_ranker
from myspellchecker.core.config import RankerConfig

ranker_config = RankerConfig()
ranker = create_base_ranker(ranker_config)

PhoneticFactory

PhoneticHasherFactory is a type alias for Callable[[ServiceContainer], Optional[PhoneticHasher]]. Use create_phonetic_hasher_factory() to get the factory function:
from myspellchecker.core.factories.phonetic_factory import create_phonetic_hasher_factory

factory_fn = create_phonetic_hasher_factory()
container.register_factory("phonetic_hasher", factory_fn)
hasher = container.get("phonetic_hasher")  # Returns None if disabled

ContextCheckerFactory

ContextCheckerFactory is a type alias for Callable[[ServiceContainer], Optional[NgramContextChecker]]. Use create_context_checker_factory() to get the factory function:
from myspellchecker.core.factories.context_checker_factory import create_context_checker_factory

factory_fn = create_context_checker_factory()
container.register_factory("context_checker", factory_fn)
checker = container.get("context_checker")  # Returns None if disabled

ComponentFactory

The high-level ComponentFactory orchestrates component creation:
from myspellchecker.core.component_factory import ComponentFactory
from myspellchecker.core.config import SpellCheckerConfig

config = SpellCheckerConfig()
factory = ComponentFactory(config)

# Create all components (requires provider and segmenter)
components = factory.create_all(provider, segmenter)

# Access individual components
viterbi_tagger = components.get("viterbi_tagger")
joint_tagger = components.get("joint_segment_tagger")
semantic_checker = components.get("semantic_checker")

Creating Custom Factories

Implement custom factories for your components:
from myspellchecker.core.factory_base import ConfigurableFactory
from myspellchecker.core.config import MyComponentConfig

class MyCustomFactory(ConfigurableFactory[MyCustomComponent, MyComponentConfig]):
    """Factory for custom component."""

    @property
    def default_config(self) -> MyComponentConfig:
        return MyComponentConfig()

    def create(
        self,
        config: Optional[MyComponentConfig] = None,
        **kwargs,
    ) -> MyCustomComponent:
        """Create component with configuration."""
        config = config or self.default_config
        return MyCustomComponent(
            option=config.my_option,
            **kwargs,
        )
Register with the container using a factory function:
def create_my_component(container):
    config = container.get_config()
    provider = container.get("provider")
    return MyCustomComponent(provider=provider, option=config.my_option)

container.register_factory("my_component", create_my_component)

Dependency Resolution

Dependencies are resolved through the container:
def create_word_validator(container: ServiceContainer):
    """Factory with dependencies."""
    config = container.get_config()

    # Resolve dependencies
    provider = container.get("provider")
    syllable_validator = container.get("syllable_validator")
    symspell = container.get("symspell")

    return WordValidator(
        config=config,
        segmenter=container.get("segmenter"),
        word_repository=provider,       # Provider implements WordRepository protocol
        syllable_repository=provider,   # Provider implements SyllableRepository protocol
        symspell=symspell,
        context_checker=container.get("context_checker"),
        suggestion_strategy=container.get("suggestion_strategy"),
    )

Testing with DI

DI makes testing easier by allowing mock injection:
from unittest.mock import Mock

# Create container with config
config = SpellCheckerConfig()
container = ServiceContainer(config)

# Register mock provider
mock_provider = Mock()
mock_provider.is_valid_word.return_value = True
container.register_factory("provider", lambda c: mock_provider)

# Component uses mock
validator = container.get("word_validator")
# validator uses mock_provider internally

Service Registration

The ServiceContainer provides service registration and discovery:
from myspellchecker.core.di import ServiceContainer

config = SpellCheckerConfig()
container = ServiceContainer(config)

# Register a factory function for a service
def create_provider(container):
    return SQLiteProvider(database_path="mydict.db")

container.register_factory("provider", create_provider)

# Get service instance (lazy initialization)
provider = container.get("provider")

Best Practices

  1. Singleton for expensive resources: Use singleton=True for database connections, caches
  2. Transient for stateful services: Use singleton=False for services with request-specific state
  3. Factory functions: Keep factory functions simple and focused
  4. Dependency declaration: Explicitly resolve dependencies in factory functions
  5. Configuration access: Use container.get_config() for configuration values

Architecture

  +------------------------------------------------------+
  | SpellChecker                                         |
  |                                                      |
  |  +------------------------------------------------+  |
  |  | ServiceContainer                               |  |
  |  |                                                |  |
  |  |  +------------------+  +------------------+    |  |
  |  |  | Provider Factory |  | SymSpell Factory |    |  |
  |  |  +------------------+  +------------------+    |  |
  |  |                                                |  |
  |  |  +--------------------+  +------------------+  |  |
  |  |  | Segmenter Factory  |  | Validators       |  |  |
  |  |  |                    |  | Factory          |  |  |
  |  |  +--------------------+  +------------------+  |  |
  |  |                                                |  |
  |  |  +------------------+  +------------------+    |  |
  |  |  | Context Factory  |  | Ranker Factory   |    |  |
  |  |  +------------------+  +------------------+    |  |
  |  |                                                |  |
  |  +------------------------------------------------+  |
  |                                                      |
  +------------------------------------------------------+

See Also