Files
markitect-main/examples/plugins/example_processor.py
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

175 lines
5.3 KiB
Python

"""
Example processor plugin for MarkiTect.
This demonstrates how to create a custom processor plugin.
"""
import re
from markitect.plugins.base import ProcessorPlugin, PluginMetadata, PluginType
from markitect.plugins.decorators import register_plugin
@register_plugin("example_processor")
class ExampleProcessor(ProcessorPlugin):
"""
Example processor that demonstrates various text processing capabilities.
This processor can:
- Convert text to different cases
- Clean up whitespace
- Remove or replace patterns
- Add prefixes/suffixes to lines
"""
@property
def metadata(self) -> PluginMetadata:
return PluginMetadata(
name="example_processor",
version="1.0.0",
description="Example processor demonstrating text transformations",
author="MarkiTect Team",
plugin_type=PluginType.PROCESSOR
)
def process(self, content: str, **kwargs) -> str:
"""
Process content with various transformations.
Args:
content: Input content to process
**kwargs: Processing options:
- case: 'upper', 'lower', 'title', 'sentence'
- clean_whitespace: bool
- remove_pattern: regex pattern to remove
- replace_pattern: dict with 'pattern' and 'replacement'
- line_prefix: string to add to start of each line
- line_suffix: string to add to end of each line
Returns:
Processed content
"""
if not isinstance(content, str):
return content
result = content
# Case transformations
case = kwargs.get('case', '').lower()
if case == 'upper':
result = result.upper()
elif case == 'lower':
result = result.lower()
elif case == 'title':
result = result.title()
elif case == 'sentence':
result = self._sentence_case(result)
# Clean whitespace
if kwargs.get('clean_whitespace', False):
result = self._clean_whitespace(result)
# Remove pattern
remove_pattern = kwargs.get('remove_pattern')
if remove_pattern:
result = re.sub(remove_pattern, '', result)
# Replace pattern
replace_pattern = kwargs.get('replace_pattern')
if replace_pattern and isinstance(replace_pattern, dict):
pattern = replace_pattern.get('pattern')
replacement = replace_pattern.get('replacement', '')
if pattern:
result = re.sub(pattern, replacement, result)
# Line prefix/suffix
line_prefix = kwargs.get('line_prefix', '')
line_suffix = kwargs.get('line_suffix', '')
if line_prefix or line_suffix:
lines = result.split('\n')
lines = [f"{line_prefix}{line}{line_suffix}" for line in lines]
result = '\n'.join(lines)
return result
def can_process(self, content: str, **kwargs) -> bool:
"""Check if content can be processed (any string content)."""
return isinstance(content, str)
def _sentence_case(self, text: str) -> str:
"""Convert text to sentence case (first letter capitalized)."""
if not text:
return text
return text[0].upper() + text[1:].lower()
def _clean_whitespace(self, text: str) -> str:
"""Clean up whitespace in text."""
# Remove trailing whitespace from each line
lines = [line.rstrip() for line in text.split('\n')]
# Remove multiple consecutive empty lines
cleaned_lines = []
prev_empty = False
for line in lines:
if line.strip():
cleaned_lines.append(line)
prev_empty = False
elif not prev_empty:
cleaned_lines.append(line)
prev_empty = True
return '\n'.join(cleaned_lines)
def validate_config(self) -> list:
"""Validate plugin configuration."""
errors = []
case = self.config.get('case', '').lower()
if case and case not in ['upper', 'lower', 'title', 'sentence']:
errors.append(f"Invalid case option: {case}")
replace_pattern = self.config.get('replace_pattern')
if replace_pattern and not isinstance(replace_pattern, dict):
errors.append("replace_pattern must be a dictionary with 'pattern' and 'replacement' keys")
return errors
# Example usage:
if __name__ == '__main__':
# Test the processor
processor = ExampleProcessor()
test_content = """ Hello World
This is a test.
Multiple empty lines above. """
# Test case conversion
result = processor.process(test_content, case='upper')
print("Upper case:")
print(result)
print()
# Test whitespace cleaning
result = processor.process(test_content, clean_whitespace=True)
print("Cleaned whitespace:")
print(repr(result))
print()
# Test pattern replacement
result = processor.process(
test_content,
replace_pattern={'pattern': r'\s+', 'replacement': ' '}
)
print("Normalized spaces:")
print(repr(result))
print()
# Test line prefix
result = processor.process(
"Line 1\nLine 2\nLine 3",
line_prefix=">> "
)
print("With prefix:")
print(result)