Files
markitect-main/markitect/plugins/README.md
tegwick b0de32d083 feat: implement comprehensive plugin architecture and extensions system (issue #19)
Complete plugin system implementation providing extensible architecture for MarkiTect:

🏗️ **Core Plugin Architecture**:
- BasePlugin abstract class with lifecycle management (initialize/cleanup)
- Specialized plugin types: ProcessorPlugin, FormatterPlugin, ValidatorPlugin, ExporterPlugin, CommandPlugin
- PluginMetadata system with version, dependencies, and type information
- Plugin initialization and configuration validation

🔍 **Plugin Discovery & Management**:
- PluginManager with automatic discovery from built-in modules and directories
- PluginRegistry for centralized plugin registration and lifecycle management
- Support for plugin loading, unloading, and reloading with configuration
- Plugin discovery from multiple sources (built-in, directories, packages)

🛠️ **CLI Integration**:
- markitect plugin-list: List all available plugins with metadata
- markitect plugin-load: Load plugins with optional configuration
- markitect plugin-unload: Unload plugins and cleanup resources
- markitect plugin-info: Show detailed plugin information
- markitect plugin-discover: Discover and refresh plugin catalog

📦 **Built-in Plugins**:
- JSON/YAML/Table formatters for output formatting
- Markdown/Text processors for content processing
- Auto-registered via @register_plugin decorator
- Comprehensive configuration options

🔧 **Developer Experience**:
- @register_plugin decorator for easy plugin registration
- Plugin configuration validation and error handling
- Comprehensive API documentation with examples
- Plugin development guide and best practices

📋 **Example Plugins**:
- Advanced text processor with case conversion and pattern replacement
- XML/CSV formatters demonstrating custom output formats
- Complete examples showing plugin development patterns

🧪 **Test Coverage**:
- 59 comprehensive tests covering all plugin functionality
- Tests for plugin lifecycle, registration, discovery, and CLI integration
- Error handling and edge case coverage
- Built-in plugin validation

Technical Implementation:
- Plugin types: processor, formatter, validator, exporter, generator, importer, transformer, extension, backend, command
- Configuration-driven plugin management with YAML/JSON support
- Graceful error handling and plugin isolation
- Plugin dependency validation and compatibility checking

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-03 11:23:32 +02:00

424 lines
9.7 KiB
Markdown

# MarkiTect Plugin System
The MarkiTect Plugin System provides a flexible and extensible architecture for adding custom functionality to MarkiTect. Plugins can extend processors, formatters, validators, exporters, and more.
## Plugin Types
### Supported Plugin Types
- **Processor**: Content processors (markdown, text transformation, etc.)
- **Formatter**: Output formatters (JSON, YAML, tables, etc.)
- **Validator**: Content validators (schema validation, lint checking, etc.)
- **Exporter**: Export handlers (PDF, HTML, etc.)
- **Generator**: Content generators (templates, stubs, etc.)
- **Importer**: Import handlers (various formats)
- **Transformer**: Content transformers (data manipulation, etc.)
- **Extension**: General extensions (any functionality)
- **Backend**: Storage/API backends (databases, APIs, etc.)
- **Command**: CLI command extensions
## Quick Start
### Creating a Simple Plugin
```python
from markitect.plugins import BasePlugin, PluginMetadata, PluginType, register_plugin
@register_plugin("my_processor")
class MyProcessor(ProcessorPlugin):
@property
def metadata(self) -> PluginMetadata:
return PluginMetadata(
name="my_processor",
version="1.0.0",
description="My custom processor",
author="Your Name",
plugin_type=PluginType.PROCESSOR
)
def process(self, content: str, **kwargs) -> str:
# Your processing logic here
return content.upper()
```
### Using Plugins via CLI
```bash
# List all available plugins
markitect plugin-list
# Load a specific plugin
markitect plugin-load my_processor
# Get plugin information
markitect plugin-info my_processor
# Discover new plugins
markitect plugin-discover --refresh
```
### Using Plugins Programmatically
```python
from markitect.plugins import PluginManager
# Initialize plugin manager
manager = PluginManager()
# Discover and load plugins
manager.discover_plugins()
processor = manager.load_plugin("my_processor")
# Use the plugin
if processor:
result = processor.process("hello world")
print(result) # HELLO WORLD
```
## Plugin Development Guide
### 1. Choose Base Class
Select the appropriate base class for your plugin:
```python
from markitect.plugins.base import (
ProcessorPlugin, # For content processing
FormatterPlugin, # For output formatting
ValidatorPlugin, # For content validation
ExporterPlugin, # For export functionality
CommandPlugin, # For CLI commands
BasePlugin # For general extensions
)
```
### 2. Implement Required Methods
Each plugin type has specific methods you must implement:
#### ProcessorPlugin
```python
class MyProcessor(ProcessorPlugin):
def process(self, content: str, **kwargs) -> str:
"""Process content and return result."""
return processed_content
def can_process(self, content: str, **kwargs) -> bool:
"""Check if this processor can handle the content."""
return True # or your logic
```
#### FormatterPlugin
```python
class MyFormatter(FormatterPlugin):
def format(self, data: Any, **kwargs) -> str:
"""Format data to string representation."""
return formatted_string
def get_file_extension(self) -> str:
"""Get file extension for this format."""
return '.txt'
```
#### ValidatorPlugin
```python
class MyValidator(ValidatorPlugin):
def validate(self, content: str, **kwargs) -> List[str]:
"""Validate content and return list of errors."""
errors = []
# Your validation logic
return errors
```
### 3. Add Metadata
```python
@property
def metadata(self) -> PluginMetadata:
return PluginMetadata(
name="plugin_name",
version="1.0.0",
description="Plugin description",
author="Your Name",
plugin_type=PluginType.PROCESSOR, # Choose appropriate type
dependencies=["optional", "list", "of", "dependencies"],
markitect_version=">=0.1.0"
)
```
### 4. Register Plugin
Use the decorator for automatic registration:
```python
@register_plugin("plugin_name")
class MyPlugin(BasePlugin):
# Implementation
```
Or register manually:
```python
from markitect.plugins import plugin_registry
plugin_registry.register(MyPlugin, "plugin_name")
```
## Configuration
### Plugin Configuration File
Create a configuration file (`.markitect/plugins.yml`) to manage plugins:
```yaml
plugin_directories:
- "plugins"
- ".markitect/plugins"
- "~/.markitect/plugins"
auto_discover: true
auto_load_enabled: true
plugins:
my_processor:
enabled: true
config:
option1: value1
option2: value2
json_formatter:
enabled: true
config:
indent: 4
```
### Plugin Configuration in Code
```python
# Load plugin with configuration
config = {"option1": "value1", "option2": "value2"}
plugin = manager.load_plugin("my_processor", config)
# Access configuration in plugin
class MyProcessor(ProcessorPlugin):
def process(self, content: str, **kwargs) -> str:
option1 = self.config.get('option1', 'default')
# Use configuration
return processed_content
```
## Built-in Plugins
MarkiTect includes several built-in plugins:
### Formatters
- `json_formatter`: Format output as JSON
- `yaml_formatter`: Format output as YAML
- `table_formatter`: Format output as ASCII tables
### Processors
- `markdown_processor`: Process markdown content
- `text_processor`: Process generic text content
## Plugin Discovery
Plugins are discovered from:
1. **Built-in plugins**: `markitect.plugins.builtin.*`
2. **Local directories**: Configured plugin directories
3. **Installed packages**: Python packages with entry points (future)
### Plugin Directory Structure
```
plugins/
├── my_plugin.py # Single file plugin
├── complex_plugin/ # Multi-file plugin
│ ├── __init__.py
│ ├── main.py
│ └── utils.py
└── another_plugin.py
```
## Advanced Features
### Plugin Dependencies
Specify dependencies in metadata:
```python
PluginMetadata(
# ...
dependencies=["requests", "pyyaml"],
markitect_version=">=0.2.0"
)
```
### Plugin Initialization and Cleanup
```python
class MyPlugin(BasePlugin):
def _initialize(self) -> None:
"""Called when plugin is loaded."""
self.connection = setup_connection()
def cleanup(self) -> None:
"""Called when plugin is unloaded."""
if hasattr(self, 'connection'):
self.connection.close()
```
### Configuration Validation
```python
def validate_config(self) -> List[str]:
"""Validate plugin configuration."""
errors = []
if 'required_option' not in self.config:
errors.append("Missing required_option")
return errors
```
### Command Plugins
Extend the CLI with custom commands:
```python
import click
class MyCommandPlugin(CommandPlugin):
def get_commands(self) -> Dict[str, Any]:
return {
'my-command': self.my_command
}
@click.command()
@click.argument('input_file')
def my_command(self, input_file):
"""My custom command."""
click.echo(f"Processing {input_file}")
```
## Best Practices
### 1. Error Handling
```python
def process(self, content: str, **kwargs) -> str:
try:
return self._do_processing(content)
except Exception as e:
# Log error but don't crash
self.logger.error(f"Processing failed: {e}")
return content # Return original content
```
### 2. Configuration Defaults
```python
def _initialize(self) -> None:
# Set defaults for configuration
defaults = {
'timeout': 30,
'retries': 3,
'format': 'json'
}
for key, value in defaults.items():
if key not in self.config:
self.config[key] = value
```
### 3. Graceful Degradation
```python
def can_process(self, content: str, **kwargs) -> bool:
"""Only claim we can process if we actually can."""
try:
# Test if content is processable
return self._test_content(content)
except Exception:
return False
```
### 4. Documentation
Always provide clear documentation for your plugins:
```python
class MyProcessor(ProcessorPlugin):
"""
Advanced text processor for MarkiTect.
This processor provides advanced text transformation capabilities
including normalization, cleanup, and format conversion.
Configuration:
normalize_whitespace (bool): Normalize whitespace (default: True)
remove_comments (bool): Remove comment lines (default: False)
encoding (str): Text encoding (default: 'utf-8')
Example:
processor = MyProcessor({
'normalize_whitespace': True,
'remove_comments': True
})
result = processor.process(content)
"""
```
## Testing Plugins
Create comprehensive tests for your plugins:
```python
import pytest
from markitect.plugins import plugin_registry
def test_my_processor():
# Load plugin
plugin = plugin_registry.get_plugin("my_processor")
assert plugin is not None
# Test processing
result = plugin.process("test content")
assert result == "expected result"
# Test error handling
result = plugin.process(None)
assert result is not None
```
## Troubleshooting
### Common Issues
1. **Plugin not discovered**: Check plugin directory configuration
2. **Import errors**: Ensure all dependencies are installed
3. **Registration fails**: Check plugin class inheritance
4. **Plugin not loading**: Check `_initialize()` method
### Debug Mode
Enable verbose logging to debug plugin issues:
```bash
markitect --verbose plugin-list
markitect --verbose plugin-load my_plugin
```
### Plugin Validation
```bash
# Validate specific plugin
markitect plugin-info my_plugin
# Discover and validate all plugins
markitect plugin-discover --refresh
```