Hub
provide.foundation.hub
¶
Provide Foundation Hub - Component and Command Coordination System¶
The hub module provides a unified system for registering, discovering, and managing components and CLI commands across the provide-io ecosystem.
Key Features: - Multi-dimensional component registry - CLI command registration and discovery - Entry point discovery - Integration with Click framework - Type-safe decorators using Python 3.11+ features
Example Usage
from provide.foundation.hub import Hub, register_command
class MyResource: def init(self, name: str): self.name = name
@register_command("init") def init_command(): pass
hub = Hub() hub.add_component(MyResource, name="my_resource", version="1.0.0") resource_class = hub.get_component("my_resource") command = hub.get_command("init")
Classes¶
AsyncContextResource
¶
Bases: AbstractAsyncContextManager[Any]
Base class for async context-managed resources.
Initialize with a resource factory.
Source code in provide/foundation/hub/protocols.py
Functions¶
__aenter__
async
¶
__aexit__
async
¶
Exit async context and cleanup resource.
Source code in provide/foundation/hub/protocols.py
AsyncInitializable
¶
Bases: Protocol
Protocol for components that support async lazy initialization.
AsyncResourceManager
¶
ComponentCategory
¶
Bases: Enum
Predefined component categories for Foundation.
These are the standard dimension values used internally by Foundation. External components can still use custom string dimensions for compatibility.
Container
¶
Dependency Injection Container.
A focused API for dependency injection patterns, wrapping the Hub with a simpler interface for type-based registration and resolution.
This container follows the Composition Root pattern where all dependencies are registered at application startup and then resolved as needed.
Example
container = Container() container.register(DatabaseClient, db_instance) container.register(HTTPClient, http_instance)
Resolve with automatic dependency injection¶
service = container.resolve(MyService)
MyService.init(db, http) called automatically¶
Pattern
The Container is designed for the Composition Root pattern: 1. Create container at app startup (main.py) 2. Register all core dependencies 3. Resolve application entry points 4. Pass dependencies explicitly (no global access)
This matches the idiomatic patterns in Go and Rust, making it easier to adopt for developers from those ecosystems.
Initialize the DI container.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
hub
|
Hub | None
|
Optional Hub instance (creates new if not provided) |
None
|
registry
|
Registry | None
|
Optional Registry instance (creates new if not provided) |
None
|
Source code in provide/foundation/hub/container.py
Functions¶
__enter__
¶
Context manager entry.
Example
with Container() as container: ... container.register(Database, db) ... service = container.resolve(MyService)
__exit__
¶
clear
¶
Clear all registered dependencies.
Warning
This clears the underlying Hub registry. Use with caution.
get
¶
Get a registered instance by type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type_hint
|
type[T]
|
Type to retrieve |
required |
Returns:
| Type | Description |
|---|---|
T | None
|
Registered instance or None if not found |
Example
db = container.get(Database)
Source code in provide/foundation/hub/container.py
has
¶
register
¶
Register a dependency by type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type_hint
|
type[T]
|
Type to register under |
required |
instance
|
T
|
Instance to register |
required |
name
|
str | None
|
Optional name for named registration |
None
|
Returns:
| Type | Description |
|---|---|
Container
|
Self for method chaining |
Example
container.register(Database, db).register(Cache, cache)
Source code in provide/foundation/hub/container.py
resolve
¶
Resolve a class with dependency injection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cls
|
type[T]
|
Class to instantiate |
required |
**overrides
|
Any
|
Explicitly provided dependencies |
{}
|
Returns:
| Type | Description |
|---|---|
T
|
New instance with dependencies injected |
Example
service = container.resolve(MyService)
Or with overrides:¶
service = container.resolve(MyService, logger=custom_logger)
Source code in provide/foundation/hub/container.py
Disposable
¶
HealthCheckable
¶
Hub
¶
Hub(
context: CLIContext | None = None,
component_registry: Registry | None = None,
command_registry: Registry | None = None,
use_shared_registries: bool = False,
)
Bases: CoreHub
Central hub for managing components, commands, and Foundation integration.
The Hub provides a unified interface for: - Registering components and commands - Discovering plugins via entry points - Creating Click CLI applications - Managing component lifecycle - Foundation system initialization
Example
hub = Hub() hub.add_component(MyResource, "resource") hub.add_command(init_cmd, "init") hub.initialize_foundation()
Create CLI with all commands¶
cli = hub.create_cli() cli()
Initialize the hub.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
CLIContext | None
|
Foundation CLIContext for configuration |
None
|
component_registry
|
Registry | None
|
Custom component registry |
None
|
command_registry
|
Registry | None
|
Custom command registry |
None
|
use_shared_registries
|
bool
|
If True, use global shared registries |
False
|
Source code in provide/foundation/hub/manager.py
Functions¶
clear
¶
Clear registrations and dispose of resources properly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dimension
|
str | None
|
Optional dimension to clear (None = all) |
None
|
Source code in provide/foundation/hub/manager.py
dispose_all
¶
Dispose of all managed resources without clearing registrations.
get_foundation_config
¶
get_foundation_logger
¶
Get Foundation logger instance through Hub.
Auto-initializes Foundation if not already done. Thread-safe with fallback behavior.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | None
|
Logger name (e.g., module name) |
None
|
Returns:
| Type | Description |
|---|---|
Any
|
Configured logger instance |
Source code in provide/foundation/hub/manager.py
initialize_foundation
¶
Initialize Foundation system through Hub.
Single initialization method replacing all setup_* functions. Thread-safe and idempotent, unless force=True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Any
|
Optional TelemetryConfig (defaults to from_env) |
None
|
force
|
bool
|
If True, force re-initialization even if already initialized |
False
|
Source code in provide/foundation/hub/manager.py
is_foundation_initialized
¶
Initializable
¶
Registry
¶
Multi-dimensional registry for storing and retrieving objects.
Supports hierarchical organization by dimension (component, command, etc.) and name within each dimension. This is a generic registry that can be used for any type of object storage and retrieval.
Thread-safe: All operations are protected by an RLock for safe concurrent access.
Note: Uses threading.RLock (not asyncio.Lock) for thread safety. For async-only applications with high-frequency registry access in request hot-paths (>10k req/sec with runtime registration), consider using an async-native registry implementation with asyncio.Lock. For typical use cases (initialization-time registration, CLI apps, read-heavy workloads), the threading lock has negligible impact.
See: docs/architecture/design-decisions.md#threading-model
Initialize an empty registry.
Source code in provide/foundation/hub/registry.py
Functions¶
__contains__
¶
Check if an item exists in the registry.
Source code in provide/foundation/hub/registry.py
__iter__
¶
Iterate over all registry entries.
Source code in provide/foundation/hub/registry.py
__len__
¶
clear
¶
Clear the registry or a specific dimension.
Source code in provide/foundation/hub/registry.py
dispose_all
¶
get
¶
Get an item from the registry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Name or alias of the item |
required |
dimension
|
str | None
|
Optional dimension to search in |
None
|
Returns:
| Type | Description |
|---|---|
Any | None
|
The registered value or None if not found |
Source code in provide/foundation/hub/registry.py
get_by_type
¶
Get a registered instance by its type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type_hint
|
type[Any]
|
Type to look up |
required |
Returns:
| Type | Description |
|---|---|
Any | None
|
Registered instance or None if not found |
Example
db = registry.get_by_type(DatabaseClient)
Source code in provide/foundation/hub/registry.py
get_entry
¶
Get the full registry entry.
Source code in provide/foundation/hub/registry.py
list_all
¶
list_dimension
¶
list_types
¶
register
¶
register(
name: str,
value: Any,
dimension: str = "default",
metadata: dict[str, Any] | None = None,
aliases: list[str] | None = None,
replace: bool = False,
) -> RegistryEntry
Register an item in the registry.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Unique name within the dimension |
required |
value
|
Any
|
The item to register |
required |
dimension
|
str
|
Registry dimension for categorization |
'default'
|
metadata
|
dict[str, Any] | None
|
Optional metadata about the item |
None
|
aliases
|
list[str] | None
|
Optional list of aliases for this item |
None
|
replace
|
bool
|
Whether to replace existing entries |
False
|
Returns:
| Type | Description |
|---|---|
RegistryEntry
|
The created registry entry |
Raises:
| Type | Description |
|---|---|
ValueError
|
If name already exists and replace=False |
Source code in provide/foundation/hub/registry.py
register_type
¶
Register an instance by its type for dependency injection.
This enables type-based lookup which is essential for DI patterns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
type_hint
|
type[Any]
|
Type to register under |
required |
instance
|
Any
|
Instance to register |
required |
name
|
str | None
|
Optional name for standard registry (defaults to type name) |
None
|
Example
registry.register_type(DatabaseClient, db_instance) db = registry.get_by_type(DatabaseClient)
Source code in provide/foundation/hub/registry.py
remove
¶
Remove an item from the registry.
Returns:
| Type | Description |
|---|---|
bool
|
True if item was removed, False if not found |
Source code in provide/foundation/hub/registry.py
RegistryEntry
¶
ResourceManager
¶
Functions¶
clear_hub
¶
Clear the global hub instance.
This is primarily used for testing to reset Foundation state between test runs.
Source code in provide/foundation/hub/manager.py
create_container
¶
Create a new DI container.
Convenience function for creating containers.
Returns:
| Type | Description |
|---|---|
Container
|
New Container instance |
Example
container = create_container() container.register(Database, db_instance)
Source code in provide/foundation/hub/container.py
get_component_registry
¶
get_hub
¶
Get the global shared hub instance (singleton pattern).
This function acts as the Composition Root for the global singleton instance. It is maintained for backward compatibility and convenience.
Note: For building testable and maintainable applications, the recommended
approach is to use a Container or Hub instance created at your application's
entry point for explicit dependency management. This global accessor should be
avoided in application code.
Thread-safe: Uses double-checked locking pattern for efficient lazy initialization.
Auto-Initialization Behavior: This function automatically initializes the Foundation system on first access. The initialization is: - Idempotent: Safe to call multiple times - Thread-safe: Uses lock manager for coordination - Lazy: Only happens on first access
Returns:
| Type | Description |
|---|---|
Hub
|
Global Hub instance (created and initialized if needed) |
Example
hub = get_hub() hub.register_command("my_command", my_function)
Note
For isolated Hub instances (testing, advanced use cases), use:
hub = Hub(use_shared_registries=False)
Source code in provide/foundation/hub/manager.py
injectable
¶
Mark a class as injectable for dependency injection.
This decorator indicates that the class follows DI patterns and can be automatically instantiated by the Hub's resolve() method.
The decorator: - Validates that init has type hints for all parameters - Marks the class as injectable for documentation purposes - Does not modify the class behavior (zero runtime overhead)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cls
|
type[T]
|
Class to mark as injectable |
required |
Returns:
| Type | Description |
|---|---|
type[T]
|
The same class, marked as injectable |
Raises:
| Type | Description |
|---|---|
ValidationError
|
If init lacks proper type hints |
Example
@injectable class UserService: ... def init(self, db: Database, cache: Cache): ... self.db = db ... self.cache = cache
Source code in provide/foundation/hub/injection.py
is_injectable
¶
Check if a class is marked as injectable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cls
|
type[Any]
|
Class to check |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if class is marked with @injectable decorator |
Source code in provide/foundation/hub/injection.py
register_command
¶
register_command(
name_or_func: str | F | None = None,
*,
description: str | None = None,
aliases: list[str] | None = None,
hidden: bool = False,
category: str | None = None,
group: bool = False,
replace: bool = False,
registry: Registry | None = None,
**metadata: Any
) -> Any
Register a CLI command in the hub.
Can be used as a decorator with or without arguments:
@register_command
def my_command():
pass
@register_command("custom-name", aliases=["cn"], category="utils")
def my_command():
pass
# Nested commands using dot notation - groups are auto-created
@register_command("container.status")
def container_status():
pass
@register_command("container.volumes.backup")
def container_volumes_backup():
pass
# Explicit group with custom description (optional)
@register_command("container", group=True, description="Container management")
def container_group():
pass
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name_or_func
|
str | F | None
|
Command name using dot notation for nesting (e.g., "container.status") |
None
|
description
|
str | None
|
Command description (defaults to docstring) |
None
|
aliases
|
list[str] | None
|
Alternative names for the command |
None
|
hidden
|
bool
|
Whether to hide from help listing |
False
|
category
|
str | None
|
Command category for grouping |
None
|
group
|
bool
|
Whether this is a command group (not a command) |
False
|
replace
|
bool
|
Whether to replace existing registration |
False
|
registry
|
Registry | None
|
Custom registry (defaults to global) |
None
|
**metadata
|
Any
|
Additional metadata stored in CommandInfo.metadata |
{}
|
Returns:
| Type | Description |
|---|---|
Any
|
Decorator function or decorated function |
Source code in provide/foundation/hub/decorators.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | |