cjm-plugin-system


Namecjm-plugin-system JSON
Version 0.0.4 PyPI version JSON
download
home_pagehttps://github.com/cj-mills/cjm-plugin-system
SummaryGeneric plugin system with discovery, configuration validation, and runtime management for extensible Python applications.
upload_time2025-10-24 00:28:12
maintainerNone
docs_urlNone
authorChristian J. Mills
requires_python>=3.9
licenseApache Software License 2.0
keywords nbdev jupyter notebook python
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # cjm-plugin-system


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Install

``` bash
pip install cjm_plugin_system
```

## Project Structure

    nbs/
    ├── core/ (3)
    │   ├── interface.ipynb  # Abstract base class defining the generic plugin interface
    │   ├── manager.ipynb    # Plugin discovery, loading, and lifecycle management system
    │   └── metadata.ipynb   # Data structures for plugin metadata
    └── utils/ (1)
        └── validation.ipynb  # JSON Schema validation helpers for plugin configuration

Total: 4 notebooks across 2 directories

## Module Dependencies

``` mermaid
graph LR
    core_interface[core.interface<br/>Plugin Interface]
    core_manager[core.manager<br/>Plugin Manager]
    core_metadata[core.metadata<br/>Plugin Metadata]
    utils_validation[utils.validation<br/>Configuration Validation]

    core_interface --> utils_validation
    core_manager --> core_metadata
    core_manager --> core_interface
```

*3 cross-module dependencies detected*

## CLI Reference

No CLI commands found in this project.

## Module Overview

Detailed documentation for each module in the project:

### Plugin Interface (`interface.ipynb`)

> Abstract base class defining the generic plugin interface

#### Import

``` python
from cjm_plugin_system.core.interface import (
    PluginInterface,
    PluginInterface_supports_streaming,
    PluginInterface_execute_stream
)
```

#### Functions

``` python
def PluginInterface_supports_streaming(self) -> bool: # True if execute_stream is implemented
    """Check if this plugin supports streaming execution."""
    # Default: check if execute_stream is overridden from the base class
    "Check if this plugin supports streaming execution."
```

``` python
def PluginInterface_execute_stream(
    self,
    *args, # Arguments for plugin execution
    **kwargs # Keyword arguments for plugin execution
) -> Generator[Any, None, Any]: # Yields partial results, returns final result
    "Stream execution results chunk by chunk."
```

#### Classes

``` python
class PluginInterface(ABC):
    "Generic plugin interface that all plugins must implement."
    
    def name(self) -> str: # Unique identifier for this plugin
            """Unique plugin identifier."""
            pass
    
        @property
        @abstractmethod
        def version(self) -> str: # Semantic version string (e.g., "1.0.0")
        "Unique plugin identifier."
    
    def version(self) -> str: # Semantic version string (e.g., "1.0.0")
            """Plugin version."""
            pass
    
        @abstractmethod
        def initialize(
            self,
            config:Optional[Dict[str, Any]]=None # Configuration dictionary for plugin-specific settings
        ) -> None
        "Plugin version."
    
    def initialize(
            self,
            config:Optional[Dict[str, Any]]=None # Configuration dictionary for plugin-specific settings
        ) -> None
        "Initialize the plugin with configuration."
    
    def execute(
            self,
            *args,
            **kwargs
        ) -> Any: # Plugin-specific output
        "Execute the plugin's main functionality."
    
    def is_available(self) -> bool: # True if all required dependencies are available
            """Check if the plugin's dependencies are available."""
            pass
    
        @staticmethod
        @abstractmethod
        def get_config_schema() -> Dict[str, Any]: # JSON Schema describing configuration options
        "Check if the plugin's dependencies are available."
    
    def get_config_schema() -> Dict[str, Any]: # JSON Schema describing configuration options
            """Return JSON Schema describing the plugin's configuration options."""
            pass
    
        @abstractmethod
        def get_current_config(self) -> Dict[str, Any]: # Current configuration state
        "Return JSON Schema describing the plugin's configuration options."
    
    def get_current_config(self) -> Dict[str, Any]: # Current configuration state
            """Return the current configuration state."""
            pass
    
        def validate_config(
            self,
            config:Dict[str, Any] # Configuration to validate
        ) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)
        "Return the current configuration state."
    
    def validate_config(
            self,
            config:Dict[str, Any] # Configuration to validate
        ) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)
        "Validate a configuration dictionary against the schema."
    
    def get_config_defaults(self) -> Dict[str, Any]: # Default values from schema
            """Extract default values from the configuration schema."""
            schema = self.get_config_schema()
            return extract_defaults(schema)
    
        def cleanup(self) -> None
        "Extract default values from the configuration schema."
    
    def cleanup(self) -> None
        "Optional cleanup when plugin is unloaded."
```

### Plugin Manager (`manager.ipynb`)

> Plugin discovery, loading, and lifecycle management system

#### Import

``` python
from cjm_plugin_system.core.manager import (
    PluginManager,
    get_plugin_config_schema,
    get_plugin_config,
    update_plugin_config,
    validate_plugin_config,
    get_all_plugin_schemas,
    reload_plugin,
    execute_plugin_stream,
    check_streaming_support,
    get_streaming_plugins
)
```

#### Functions

``` python
def get_plugin_config_schema(
    self,
    plugin_name:str # Name of the plugin
) -> Optional[Dict[str, Any]]: # Configuration schema or None if plugin not found
    "Get the configuration schema for a plugin."
```

``` python
def get_plugin_config(
    self,
    plugin_name:str # Name of the plugin
) -> Optional[Dict[str, Any]]: # Current configuration or None if plugin not found
    "Get the current configuration of a plugin."
```

``` python
def update_plugin_config(
    self,
    plugin_name:str, # Name of the plugin
    config:Dict[str, Any], # New configuration
    merge:bool=True # Whether to merge with existing config or replace entirely
) -> bool: # True if successful, False otherwise
    "Update a plugin's configuration and reinitialize it."
```

``` python
def validate_plugin_config(
    self,
    plugin_name:str, # Name of the plugin
    config:Dict[str, Any] # Configuration to validate
) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)
    "Validate a configuration dictionary for a plugin without applying it."
```

``` python
def get_all_plugin_schemas(
    self
) -> Dict[str, Dict[str, Any]]: # Dictionary mapping plugin names to their schemas
    "Get configuration schemas for all loaded plugins."
```

``` python
def reload_plugin(
    self,
    plugin_name:str, # Name of the plugin to reload
    config:Optional[Dict[str, Any]]=None # Optional new configuration
) -> bool: # True if successful, False otherwise
    "Reload a plugin with optional new configuration."
```

``` python
def execute_plugin_stream(
    self,
    plugin_name:str, # Name of the plugin to execute
    *args, # Arguments to pass to the plugin
    **kwargs # Keyword arguments to pass to the plugin
) -> Generator[Any, None, Any]: # Generator yielding partial results, returns final result
    "Execute a plugin with streaming support if available."
```

``` python
def check_streaming_support(
    self,
    plugin_name:str # Name of the plugin to check
) -> bool: # True if plugin supports streaming
    "Check if a plugin supports streaming execution."
```

``` python
def get_streaming_plugins(
    self
) -> List[str]: # List of plugin names that support streaming
    "Get a list of all loaded plugins that support streaming."
```

#### Classes

``` python
class PluginManager:
    def __init__(
        self,
        plugin_interface:Type[PluginInterface]=PluginInterface, # Base class/interface plugins must implement
        entry_point_group:Optional[str]=None # Optional override for entry point group name
    )
    "Manages plugin discovery, loading, and lifecycle."
    
    def __init__(
            self,
            plugin_interface:Type[PluginInterface]=PluginInterface, # Base class/interface plugins must implement
            entry_point_group:Optional[str]=None # Optional override for entry point group name
        )
        "Initialize the plugin manager."
    
    def get_entry_points(self) -> importlib.metadata.EntryPoints: # Entry points for the configured group
            """Get plugin entry points from installed packages."""
            self.entry_points = []
            try
        "Get plugin entry points from installed packages."
    
    def discover_plugins(self) -> List[PluginMeta]: # List of discovered plugin metadata objects
            """Discover all installed plugins via entry points."""
            self.discovered = []
    
            for ep in self.entry_points
        "Discover all installed plugins via entry points."
    
    def load_plugin(
            self,
            plugin_meta:PluginMeta, # Plugin metadata
            config:Optional[Dict[str, Any]]=None # Optional configuration for the plugin
        ) -> bool: # True if successfully loaded, False otherwise
        "Load and initialize a plugin."
    
    def load_plugin_from_module(
            self,
            module_path:str, # Path to the Python module
            config:Optional[Dict[str, Any]]=None # Optional configuration for the plugin
        ) -> bool: # True if successfully loaded, False otherwise
        "Load a plugin directly from a Python module file or package."
    
    def unload_plugin(
            self,
            plugin_name:str # Name of the plugin to unload
        ) -> bool: # True if successfully unloaded, False otherwise
        "Unload a plugin and call its cleanup method."
    
    def get_plugin(
            self,
            plugin_name:str # Name of the plugin to retrieve
        ) -> Optional[PluginInterface]: # Plugin instance if found, None otherwise
        "Get a loaded plugin instance by name."
    
    def list_plugins(self) -> List[PluginMeta]: # List of metadata for all loaded plugins
            """List all loaded plugins."""
            return list(self.plugins.values())
    
        def execute_plugin(
            self,
            plugin_name:str, # Name of the plugin to execute
            *args, # Arguments to pass to the plugin
            **kwargs # Keyword arguments to pass to the plugin
        ) -> Any: # Result of the plugin execution
        "List all loaded plugins."
    
    def execute_plugin(
            self,
            plugin_name:str, # Name of the plugin to execute
            *args, # Arguments to pass to the plugin
            **kwargs # Keyword arguments to pass to the plugin
        ) -> Any: # Result of the plugin execution
        "Execute a plugin's main functionality."
    
    def enable_plugin(
            self,
            plugin_name:str # Name of the plugin to enable
        ) -> bool: # True if plugin was enabled, False if not found
        "Enable a plugin."
    
    def disable_plugin(
            self,
            plugin_name:str # Name of the plugin to disable
        ) -> bool: # True if plugin was disabled, False if not found
        "Disable a plugin without unloading it."
```

### Plugin Metadata (`metadata.ipynb`)

> Data structures for plugin metadata

#### Import

``` python
from cjm_plugin_system.core.metadata import (
    PluginMeta
)
```

#### Classes

``` python
@dataclass
class PluginMeta:
    "Metadata about a plugin."
    
    name: str  # Plugin's unique identifier
    version: str  # Plugin's version string
    description: str = ''  # Brief description of the plugin's functionality
    author: str = ''  # Plugin author's name or organization
    package_name: str = ''  # Python package name containing the plugin
    instance: Optional[Any]  # Plugin instance (PluginInterface subclass)
    enabled: bool = True  # Whether the plugin is enabled
```

### Configuration Validation (`validation.ipynb`)

> JSON Schema validation helpers for plugin configuration

#### Import

``` python
from cjm_plugin_system.utils.validation import (
    validate_config,
    extract_defaults
)
```

#### Functions

``` python
def validate_config(
    config:Dict[str, Any], # Configuration to validate
    schema:Dict[str, Any] # JSON Schema to validate against
) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)
    "Validate a configuration dictionary against a JSON Schema."
```

``` python
def _basic_validate(
    config:Dict[str, Any], # Configuration to validate
    schema:Dict[str, Any] # JSON Schema to validate against
) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)
    "Basic validation without jsonschema library."
```

``` python
def extract_defaults(
    schema:Dict[str, Any] # JSON Schema
) -> Dict[str, Any]: # Default values from schema
    "Extract default values from a JSON Schema."
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/cj-mills/cjm-plugin-system",
    "name": "cjm-plugin-system",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "nbdev jupyter notebook python",
    "author": "Christian J. Mills",
    "author_email": "9126128+cj-mills@users.noreply.github.com",
    "download_url": "https://files.pythonhosted.org/packages/94/61/b3eb7811edda5a13e7ba8bbc727d86780342c57c7ac761de0a5b2c054a36/cjm_plugin_system-0.0.4.tar.gz",
    "platform": null,
    "description": "# cjm-plugin-system\n\n\n<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->\n\n## Install\n\n``` bash\npip install cjm_plugin_system\n```\n\n## Project Structure\n\n    nbs/\n    \u251c\u2500\u2500 core/ (3)\n    \u2502   \u251c\u2500\u2500 interface.ipynb  # Abstract base class defining the generic plugin interface\n    \u2502   \u251c\u2500\u2500 manager.ipynb    # Plugin discovery, loading, and lifecycle management system\n    \u2502   \u2514\u2500\u2500 metadata.ipynb   # Data structures for plugin metadata\n    \u2514\u2500\u2500 utils/ (1)\n        \u2514\u2500\u2500 validation.ipynb  # JSON Schema validation helpers for plugin configuration\n\nTotal: 4 notebooks across 2 directories\n\n## Module Dependencies\n\n``` mermaid\ngraph LR\n    core_interface[core.interface<br/>Plugin Interface]\n    core_manager[core.manager<br/>Plugin Manager]\n    core_metadata[core.metadata<br/>Plugin Metadata]\n    utils_validation[utils.validation<br/>Configuration Validation]\n\n    core_interface --> utils_validation\n    core_manager --> core_metadata\n    core_manager --> core_interface\n```\n\n*3 cross-module dependencies detected*\n\n## CLI Reference\n\nNo CLI commands found in this project.\n\n## Module Overview\n\nDetailed documentation for each module in the project:\n\n### Plugin Interface (`interface.ipynb`)\n\n> Abstract base class defining the generic plugin interface\n\n#### Import\n\n``` python\nfrom cjm_plugin_system.core.interface import (\n    PluginInterface,\n    PluginInterface_supports_streaming,\n    PluginInterface_execute_stream\n)\n```\n\n#### Functions\n\n``` python\ndef PluginInterface_supports_streaming(self) -> bool: # True if execute_stream is implemented\n    \"\"\"Check if this plugin supports streaming execution.\"\"\"\n    # Default: check if execute_stream is overridden from the base class\n    \"Check if this plugin supports streaming execution.\"\n```\n\n``` python\ndef PluginInterface_execute_stream(\n    self,\n    *args, # Arguments for plugin execution\n    **kwargs # Keyword arguments for plugin execution\n) -> Generator[Any, None, Any]: # Yields partial results, returns final result\n    \"Stream execution results chunk by chunk.\"\n```\n\n#### Classes\n\n``` python\nclass PluginInterface(ABC):\n    \"Generic plugin interface that all plugins must implement.\"\n    \n    def name(self) -> str: # Unique identifier for this plugin\n            \"\"\"Unique plugin identifier.\"\"\"\n            pass\n    \n        @property\n        @abstractmethod\n        def version(self) -> str: # Semantic version string (e.g., \"1.0.0\")\n        \"Unique plugin identifier.\"\n    \n    def version(self) -> str: # Semantic version string (e.g., \"1.0.0\")\n            \"\"\"Plugin version.\"\"\"\n            pass\n    \n        @abstractmethod\n        def initialize(\n            self,\n            config:Optional[Dict[str, Any]]=None # Configuration dictionary for plugin-specific settings\n        ) -> None\n        \"Plugin version.\"\n    \n    def initialize(\n            self,\n            config:Optional[Dict[str, Any]]=None # Configuration dictionary for plugin-specific settings\n        ) -> None\n        \"Initialize the plugin with configuration.\"\n    \n    def execute(\n            self,\n            *args,\n            **kwargs\n        ) -> Any: # Plugin-specific output\n        \"Execute the plugin's main functionality.\"\n    \n    def is_available(self) -> bool: # True if all required dependencies are available\n            \"\"\"Check if the plugin's dependencies are available.\"\"\"\n            pass\n    \n        @staticmethod\n        @abstractmethod\n        def get_config_schema() -> Dict[str, Any]: # JSON Schema describing configuration options\n        \"Check if the plugin's dependencies are available.\"\n    \n    def get_config_schema() -> Dict[str, Any]: # JSON Schema describing configuration options\n            \"\"\"Return JSON Schema describing the plugin's configuration options.\"\"\"\n            pass\n    \n        @abstractmethod\n        def get_current_config(self) -> Dict[str, Any]: # Current configuration state\n        \"Return JSON Schema describing the plugin's configuration options.\"\n    \n    def get_current_config(self) -> Dict[str, Any]: # Current configuration state\n            \"\"\"Return the current configuration state.\"\"\"\n            pass\n    \n        def validate_config(\n            self,\n            config:Dict[str, Any] # Configuration to validate\n        ) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)\n        \"Return the current configuration state.\"\n    \n    def validate_config(\n            self,\n            config:Dict[str, Any] # Configuration to validate\n        ) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)\n        \"Validate a configuration dictionary against the schema.\"\n    \n    def get_config_defaults(self) -> Dict[str, Any]: # Default values from schema\n            \"\"\"Extract default values from the configuration schema.\"\"\"\n            schema = self.get_config_schema()\n            return extract_defaults(schema)\n    \n        def cleanup(self) -> None\n        \"Extract default values from the configuration schema.\"\n    \n    def cleanup(self) -> None\n        \"Optional cleanup when plugin is unloaded.\"\n```\n\n### Plugin Manager (`manager.ipynb`)\n\n> Plugin discovery, loading, and lifecycle management system\n\n#### Import\n\n``` python\nfrom cjm_plugin_system.core.manager import (\n    PluginManager,\n    get_plugin_config_schema,\n    get_plugin_config,\n    update_plugin_config,\n    validate_plugin_config,\n    get_all_plugin_schemas,\n    reload_plugin,\n    execute_plugin_stream,\n    check_streaming_support,\n    get_streaming_plugins\n)\n```\n\n#### Functions\n\n``` python\ndef get_plugin_config_schema(\n    self,\n    plugin_name:str # Name of the plugin\n) -> Optional[Dict[str, Any]]: # Configuration schema or None if plugin not found\n    \"Get the configuration schema for a plugin.\"\n```\n\n``` python\ndef get_plugin_config(\n    self,\n    plugin_name:str # Name of the plugin\n) -> Optional[Dict[str, Any]]: # Current configuration or None if plugin not found\n    \"Get the current configuration of a plugin.\"\n```\n\n``` python\ndef update_plugin_config(\n    self,\n    plugin_name:str, # Name of the plugin\n    config:Dict[str, Any], # New configuration\n    merge:bool=True # Whether to merge with existing config or replace entirely\n) -> bool: # True if successful, False otherwise\n    \"Update a plugin's configuration and reinitialize it.\"\n```\n\n``` python\ndef validate_plugin_config(\n    self,\n    plugin_name:str, # Name of the plugin\n    config:Dict[str, Any] # Configuration to validate\n) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)\n    \"Validate a configuration dictionary for a plugin without applying it.\"\n```\n\n``` python\ndef get_all_plugin_schemas(\n    self\n) -> Dict[str, Dict[str, Any]]: # Dictionary mapping plugin names to their schemas\n    \"Get configuration schemas for all loaded plugins.\"\n```\n\n``` python\ndef reload_plugin(\n    self,\n    plugin_name:str, # Name of the plugin to reload\n    config:Optional[Dict[str, Any]]=None # Optional new configuration\n) -> bool: # True if successful, False otherwise\n    \"Reload a plugin with optional new configuration.\"\n```\n\n``` python\ndef execute_plugin_stream(\n    self,\n    plugin_name:str, # Name of the plugin to execute\n    *args, # Arguments to pass to the plugin\n    **kwargs # Keyword arguments to pass to the plugin\n) -> Generator[Any, None, Any]: # Generator yielding partial results, returns final result\n    \"Execute a plugin with streaming support if available.\"\n```\n\n``` python\ndef check_streaming_support(\n    self,\n    plugin_name:str # Name of the plugin to check\n) -> bool: # True if plugin supports streaming\n    \"Check if a plugin supports streaming execution.\"\n```\n\n``` python\ndef get_streaming_plugins(\n    self\n) -> List[str]: # List of plugin names that support streaming\n    \"Get a list of all loaded plugins that support streaming.\"\n```\n\n#### Classes\n\n``` python\nclass PluginManager:\n    def __init__(\n        self,\n        plugin_interface:Type[PluginInterface]=PluginInterface, # Base class/interface plugins must implement\n        entry_point_group:Optional[str]=None # Optional override for entry point group name\n    )\n    \"Manages plugin discovery, loading, and lifecycle.\"\n    \n    def __init__(\n            self,\n            plugin_interface:Type[PluginInterface]=PluginInterface, # Base class/interface plugins must implement\n            entry_point_group:Optional[str]=None # Optional override for entry point group name\n        )\n        \"Initialize the plugin manager.\"\n    \n    def get_entry_points(self) -> importlib.metadata.EntryPoints: # Entry points for the configured group\n            \"\"\"Get plugin entry points from installed packages.\"\"\"\n            self.entry_points = []\n            try\n        \"Get plugin entry points from installed packages.\"\n    \n    def discover_plugins(self) -> List[PluginMeta]: # List of discovered plugin metadata objects\n            \"\"\"Discover all installed plugins via entry points.\"\"\"\n            self.discovered = []\n    \n            for ep in self.entry_points\n        \"Discover all installed plugins via entry points.\"\n    \n    def load_plugin(\n            self,\n            plugin_meta:PluginMeta, # Plugin metadata\n            config:Optional[Dict[str, Any]]=None # Optional configuration for the plugin\n        ) -> bool: # True if successfully loaded, False otherwise\n        \"Load and initialize a plugin.\"\n    \n    def load_plugin_from_module(\n            self,\n            module_path:str, # Path to the Python module\n            config:Optional[Dict[str, Any]]=None # Optional configuration for the plugin\n        ) -> bool: # True if successfully loaded, False otherwise\n        \"Load a plugin directly from a Python module file or package.\"\n    \n    def unload_plugin(\n            self,\n            plugin_name:str # Name of the plugin to unload\n        ) -> bool: # True if successfully unloaded, False otherwise\n        \"Unload a plugin and call its cleanup method.\"\n    \n    def get_plugin(\n            self,\n            plugin_name:str # Name of the plugin to retrieve\n        ) -> Optional[PluginInterface]: # Plugin instance if found, None otherwise\n        \"Get a loaded plugin instance by name.\"\n    \n    def list_plugins(self) -> List[PluginMeta]: # List of metadata for all loaded plugins\n            \"\"\"List all loaded plugins.\"\"\"\n            return list(self.plugins.values())\n    \n        def execute_plugin(\n            self,\n            plugin_name:str, # Name of the plugin to execute\n            *args, # Arguments to pass to the plugin\n            **kwargs # Keyword arguments to pass to the plugin\n        ) -> Any: # Result of the plugin execution\n        \"List all loaded plugins.\"\n    \n    def execute_plugin(\n            self,\n            plugin_name:str, # Name of the plugin to execute\n            *args, # Arguments to pass to the plugin\n            **kwargs # Keyword arguments to pass to the plugin\n        ) -> Any: # Result of the plugin execution\n        \"Execute a plugin's main functionality.\"\n    \n    def enable_plugin(\n            self,\n            plugin_name:str # Name of the plugin to enable\n        ) -> bool: # True if plugin was enabled, False if not found\n        \"Enable a plugin.\"\n    \n    def disable_plugin(\n            self,\n            plugin_name:str # Name of the plugin to disable\n        ) -> bool: # True if plugin was disabled, False if not found\n        \"Disable a plugin without unloading it.\"\n```\n\n### Plugin Metadata (`metadata.ipynb`)\n\n> Data structures for plugin metadata\n\n#### Import\n\n``` python\nfrom cjm_plugin_system.core.metadata import (\n    PluginMeta\n)\n```\n\n#### Classes\n\n``` python\n@dataclass\nclass PluginMeta:\n    \"Metadata about a plugin.\"\n    \n    name: str  # Plugin's unique identifier\n    version: str  # Plugin's version string\n    description: str = ''  # Brief description of the plugin's functionality\n    author: str = ''  # Plugin author's name or organization\n    package_name: str = ''  # Python package name containing the plugin\n    instance: Optional[Any]  # Plugin instance (PluginInterface subclass)\n    enabled: bool = True  # Whether the plugin is enabled\n```\n\n### Configuration Validation (`validation.ipynb`)\n\n> JSON Schema validation helpers for plugin configuration\n\n#### Import\n\n``` python\nfrom cjm_plugin_system.utils.validation import (\n    validate_config,\n    extract_defaults\n)\n```\n\n#### Functions\n\n``` python\ndef validate_config(\n    config:Dict[str, Any], # Configuration to validate\n    schema:Dict[str, Any] # JSON Schema to validate against\n) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)\n    \"Validate a configuration dictionary against a JSON Schema.\"\n```\n\n``` python\ndef _basic_validate(\n    config:Dict[str, Any], # Configuration to validate\n    schema:Dict[str, Any] # JSON Schema to validate against\n) -> Tuple[bool, Optional[str]]: # (is_valid, error_message)\n    \"Basic validation without jsonschema library.\"\n```\n\n``` python\ndef extract_defaults(\n    schema:Dict[str, Any] # JSON Schema\n) -> Dict[str, Any]: # Default values from schema\n    \"Extract default values from a JSON Schema.\"\n```\n",
    "bugtrack_url": null,
    "license": "Apache Software License 2.0",
    "summary": "Generic plugin system with discovery, configuration validation, and runtime management for extensible Python applications.",
    "version": "0.0.4",
    "project_urls": {
        "Homepage": "https://github.com/cj-mills/cjm-plugin-system"
    },
    "split_keywords": [
        "nbdev",
        "jupyter",
        "notebook",
        "python"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "5e7cdb65291bf8bbb9f3281f52da526220fa633c4731a3d3b3c22de7e3011afe",
                "md5": "58ddb63dfe54d201337c51b3f3e89c1e",
                "sha256": "759f77a115f3d6babb8d7d3df380122a1c137f07f5085fd787ca3c64371737b4"
            },
            "downloads": -1,
            "filename": "cjm_plugin_system-0.0.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "58ddb63dfe54d201337c51b3f3e89c1e",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 18164,
            "upload_time": "2025-10-24T00:28:11",
            "upload_time_iso_8601": "2025-10-24T00:28:11.494864Z",
            "url": "https://files.pythonhosted.org/packages/5e/7c/db65291bf8bbb9f3281f52da526220fa633c4731a3d3b3c22de7e3011afe/cjm_plugin_system-0.0.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "9461b3eb7811edda5a13e7ba8bbc727d86780342c57c7ac761de0a5b2c054a36",
                "md5": "ceec567394cd51f1fe159fce56d1e1bd",
                "sha256": "376c2a8f5d8f59e583bf4d4a3d376a84d0a374cdfc1e92c4d96580414555d22b"
            },
            "downloads": -1,
            "filename": "cjm_plugin_system-0.0.4.tar.gz",
            "has_sig": false,
            "md5_digest": "ceec567394cd51f1fe159fce56d1e1bd",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 19278,
            "upload_time": "2025-10-24T00:28:12",
            "upload_time_iso_8601": "2025-10-24T00:28:12.528635Z",
            "url": "https://files.pythonhosted.org/packages/94/61/b3eb7811edda5a13e7ba8bbc727d86780342c57c7ac761de0a5b2c054a36/cjm_plugin_system-0.0.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-10-24 00:28:12",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "cj-mills",
    "github_project": "cjm-plugin-system",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "cjm-plugin-system"
}
        
Elapsed time: 0.81702s