Learn how to create custom plugins to extend Bioshift's functionality with your own specialized nodes, tools, and integrations.
Understanding how plugins integrate with Bioshift's core systems.
Understanding how plugins integrate with Bioshift
Required files and directory structure
How plugins are loaded and managed
Follow these steps to create your first Bioshift plugin.
Prepare your development workspace
# Create plugin directory
mkdir my_custom_plugin
cd my_custom_plugin
# Create manifest.json
cat > manifest.json << 'EOF'
{
"id": "my_custom_plugin",
"name": "My Custom Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "A custom plugin for Bioshift",
"entry_module": "my_plugin.py"
}
EOF
Set up the basic plugin skeleton
# Plugin directory structure
my_custom_plugin/
├── manifest.json # Plugin manifest (REQUIRED)
├── my_plugin.py # Entry module (REQUIRED)
├── icons/ # Optional custom icons
│ └── my_icon.png
└── README.md # Optional documentation
Create the plugin.json configuration file
{
"id": "my_custom_plugin",
"name": "My Custom Plugin",
"version": "1.0.0",
"author": "Your Name",
"description": "A custom plugin for Bioshift",
"entry_module": "my_plugin.py"
}
Create your custom node classes
from core.nodes import BaseNode
class MyCustomNode(BaseNode):
"""Custom node for special data processing."""
def __init__(self):
super().__init__(node_type="my_custom_node", title="My Custom Node")
# Add input ports
self.add_input_port("input_data", data_type="string")
self.add_input_port("parameters", data_type="string")
# Add output ports
self.add_output_port("processed_data", data_type="string")
self.add_output_port("statistics", data_type="string")
# Set default properties
self.set_property("processing_mode", "standard")
self.set_property("enable_logging", True)
def execute(self, inputs: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
"""Execute the node's processing logic."""
try:
# Get input data
input_data = inputs.get("input_data") if inputs else None
parameters = inputs.get("parameters", {}) if inputs else {}
if input_data is None:
raise ValueError("Input data is required")
# Process the data
processed_data, statistics = self._process_data(input_data, parameters)
# Return results
return {
"processed_data": processed_data,
"statistics": statistics
}
except Exception as e:
self.logger.error(f"Node execution failed: {str(e)}")
raise
def _process_data(self, data, parameters):
"""Implement your custom processing logic here."""
# Example processing - replace with your logic
import pandas as pd
if isinstance(data, list) and len(data) > 0:
df = pd.DataFrame(data)
elif hasattr(data, '__iter__'):
df = pd.DataFrame(list(data))
else:
raise ValueError("Invalid input data format")
# Apply your processing
processed_df = self._apply_custom_processing(df, parameters)
# Calculate statistics
stats = {
'rows_processed': len(processed_df),
'columns': list(processed_df.columns),
'processing_mode': self.get_property("processing_mode")
}
return processed_df, stats
def _apply_custom_processing(self, df, parameters):
"""Implement your specific data processing logic."""
# This is where your custom logic goes
# Example: add a new calculated column
df['custom_score'] = df.mean(axis=1)
return df
def _inline_summary(self) -> list[str]:
"""Display node status in the canvas."""
mode = self.get_property("processing_mode")
return [
f"Mode: {mode}",
f"Logging: {'Enabled' if self.get_property('enable_logging') else 'Disabled'}"
]
Make your plugin discoverable by Bioshift
def register(api):
"""Register plugin nodes with Bioshift."""
api.register_node(
node_type="my_custom_node",
node_class=MyCustomNode,
display_name="My Custom Node",
description="A custom node for data processing",
category="Examples",
icon_relpath="icons/my_icon.png"
)
Ensure your plugin works correctly
# Testing your plugin:
1. In Bioshift, go to Plugins → Add Plugin…
2. Select your plugin folder
3. Choose Plugins → Reload Plugins
4. Look for your node in the toolbox under the specified category
5. Create a workflow and test the node functionality
# If you encounter issues:
- Check the console output for error messages
- Verify manifest.json has correct format
- Ensure entry_module matches your Python file name
- Make sure register(api) function exists and is properly implemented
Prepare your plugin for distribution
# Create ZIP archive for distribution
zip -r my_custom_plugin.zip my_custom_plugin/
# Alternative: Share the folder directly
# Users can install from folder using Plugins → Add Plugin…
# Distribution tips:
- Include a README.md with usage instructions
- Test your plugin on different systems
- Provide example workflows
- Document any dependencies
- Consider creating a GitHub repository
Take your plugin development to the next level with these advanced techniques.
Create custom user interfaces for your nodes
Advanced plugin configuration options
Robust error handling and debugging
Optimize plugin performance
Security considerations for plugin development
Get inspired by these example plugin projects of varying complexity.
Custom nodes for data manipulation and analysis
Convert between different molecular and data file formats
Specialized analysis nodes for specific research workflows