Registry Pattern¶
Plating uses a registry-based architecture for component discovery and management. This document explains how the registry works and how to interact with it.
Overview¶
The PlatingRegistry is a centralized catalog of all components and their documentation bundles. It integrates with foundation's component discovery system to automatically find and register components.
Architecture¶
PlatingRegistry
├── Component Discovery (via foundation.hub)
├── Bundle Registration (.plating directories)
├── Component Metadata (type, path, schema)
└── Statistics & Queries
How It Works¶
1. Automatic Discovery¶
When you create a Plating instance, it automatically discovers components:
from plating import Plating, PlatingContext
context = PlatingContext(provider_name="my_provider")
api = Plating(context, package_name="pyvider.components")
# Registry is automatically populated with discovered components
2. Component Registration¶
Components are registered by type and name:
# Internal registration happens automatically
registry.register(
name="my_resource",
dimension="resource", # or "data_source", "function", "provider"
value=bundle_entry
)
3. Component Queries¶
The registry provides methods to query components:
# Get all resources
resources = api.registry.get_components(ComponentType.RESOURCE)
# Get specific component
resource = api.registry.get_component(
ComponentType.RESOURCE,
"my_resource"
)
# Get components with templates
documented = api.registry.get_components_with_templates(
ComponentType.RESOURCE
)
Registry Statistics¶
Get insights into your provider's documentation:
# Via API (synchronous method)
stats = api.get_registry_stats()
# Stats include:
# - Total components by type
# - Documentation coverage
# - Bundle statistics
CLI command:
Example output:
📊 Registry Statistics
━━━━━━━━━━━━━━━━━━━━━━━━━━━
Provider: my_provider
Package: pyvider.components
Components:
Resources: 15 (12 documented)
Data Sources: 8 (8 documented)
Functions: 5 (3 documented)
Coverage: 80% (23/28)
Component Types¶
The registry organizes components into dimensions:
| Type | Dimension | Directory | Description |
|---|---|---|---|
ComponentType.RESOURCE |
"resource" | resources/ |
Terraform resources |
ComponentType.DATA_SOURCE |
"data_source" | data-sources/ |
Data sources |
ComponentType.FUNCTION |
"function" | functions/ |
Provider functions |
ComponentType.PROVIDER |
"provider" | providers/ |
Provider config |
Bundle Discovery¶
The registry finds .plating bundles in installed packages:
# Search pattern for bundles
package_name/
├── resources/
│ ├── my_resource.py
│ └── my_resource.plating/ # Discovered
├── data_sources/
│ └── my_data.plating/ # Discovered
└── functions/
└── my_function.plating/ # Discovered
Multi-Component Bundles¶
A single .plating directory can contain multiple component bundles:
components.plating/
├── resource1/
│ ├── docs/
│ └── examples/
├── resource2/
│ ├── docs/
│ └── examples/
└── data_source1/
├── docs/
└── examples/
Registry Entry Structure¶
Each registry entry contains:
PlatingRegistryEntry:
name: str # Component name
dimension: str # Component type
bundle: PlatingBundle # Bundle instance
metadata:
path: Path # Bundle directory path
component_type: str # Type identifier
has_template: bool # Has main template
has_examples: bool # Has example files
Package Filtering¶
Control which packages are searched:
# Search specific package only
api = Plating(context, package_name="pyvider.aws")
# Search all installed packages (slower)
api = Plating(context) # package_name=None
Registry Resilience¶
The registry includes foundation resilience patterns:
- Retry Policy: Automatic retries for discovery failures
- Error Recovery: Continues discovery even if some packages fail
- Deduplication: Prevents duplicate component registration
- Caching: Component metadata cached per session
Programmatic Access¶
import asyncio
from plating import Plating, PlatingContext
from plating.types import ComponentType
async def explore_registry():
context = PlatingContext(provider_name="my_provider")
api = Plating(context)
# Get all resources
resources = api.registry.get_components(ComponentType.RESOURCE)
print(f"Found {len(resources)} resources")
# Check specific component
resource = api.registry.get_component(
ComponentType.RESOURCE,
"my_resource"
)
if resource:
print(f"Resource path: {resource.plating_dir}")
print(f"Has template: {resource.has_main_template()}")
print(f"Has examples: {resource.has_examples()}")
# Get registry statistics (synchronous method)
stats = api.get_registry_stats()
print(f"Total components: {stats['total_components']}")
# Print stats by component type
for comp_type in ['resource', 'data_source', 'function']:
if comp_type in stats:
print(f"{comp_type}: {stats[comp_type]['with_templates']}/{stats[comp_type]['total']} documented")
asyncio.run(explore_registry())
Custom Discovery¶
For non-standard package structures, you can extend discovery:
from plating.discovery import PlatingDiscovery
class CustomDiscovery(PlatingDiscovery):
def discover_bundles(self):
bundles = super().discover_bundles()
# Add custom discovery logic
return bundles
Best Practices¶
- Package Organization: Follow standard structure for automatic discovery
- Naming Conventions: Use consistent naming for components and bundles
- Package Filtering: Specify package_name for faster discovery
- Cache Registry: Reuse Plating instance to avoid re-discovery
Troubleshooting¶
No Components Found¶
# Enable debug logging
import logging
logging.basicConfig(level=logging.DEBUG)
# Check discovery
context = PlatingContext(provider_name="my_provider", log_level="DEBUG")
api = Plating(context)
Duplicate Components¶
The registry automatically deduplicates components during global discovery. If you see duplicates, check for multiple installations of the same package.
Performance Issues¶
For large environments with many packages: