Contributing to Optiscope¶
Contributions are welcome! This guide outlines how you can contribute to the project.
How to Contribute¶
- New File Formats: Add handlers for solver-specific formats (NOMAD, Pymoo, etc.)
- Analysis Methods: Implement MCDA algorithms, metrics, etc.
- Page Modules: Create new visualization pages for the Dash app.
- Documentation: Improve docs, add examples, write tutorials.
Adding a New Page Module¶
The Optiscope Dash application is modular, allowing for the easy addition of new pages. Each page is a self-contained module that inherits from the PageModule base class. There are two main ways to add a new page: by developing it directly within the Optiscope project or by creating an external library that plugs into the application.
1. Creating the Page Module¶
First, you need to create a class that inherits from optiscope.dash_app.pages._base.PageModule. This class defines the page's metadata and layout.
Here is the basic structure of a page module file (e.g., page.py):
from dash import html
from optiscope.dash_app.pages._base import PageModule
class MyNewPage(PageModule):
name = "My New Page"
path = "/my-new-page"
icon = "fas fa-rocket" # Example: Font Awesome icon
description = "A short description of what this page does."
requires_data = True # Set to False if the page doesn't need optimization data
category = "Analysis" # Optional category for navigation
def layout(self, **kwargs) -> html.Div:
return html.Div([
html.H1(self.name),
html.P(self.description)
])
def register_callbacks(self, app=None):
# Register any Dash callbacks here
pass
# Create an instance of your page module
page_module = MyNewPage()
2. Integrating the Page¶
You can integrate your new page using one of the following methods:
Method A: Developing Within the Optiscope Project¶
This is the simplest method for contributing a page directly to the core project. The application's page discovery mechanism (discover_local_pages in optiscope/dash_app/core/page_registry.py) automatically finds and registers new pages that follow a specific structure.
-
Create a directory for your page inside
optiscope/dash_app/pages/. The directory name should be descriptive (e.g.,my_new_page). -
Create a
page.pyfile inside your new directory (optiscope/dash_app/pages/my_new_page/page.py). -
Define your
PageModulesubclass inpage.pyand instantiate it aspage_module, as shown in the example above.
The application will automatically detect and register your page on startup.
Method B: Creating an External Library (Plugin)¶
This method is ideal for creating extensions or plugins that can be installed as separate Python packages. The page is discovered via entry points defined in your library's pyproject.toml.
-
Set up your library structure. It can be structured however you like, but it must contain your
PageModuleimplementation. -
Define an entry point in your library's
-pyproject.tomlunder theoptiscope.pagesgroup. This tells Optiscope where to find your page module.my_page_entry_pointis a unique name for your entry point. -my_plugin.pages:page_moduleis the import path to the instance of yourPageModulesubclass.
The discover_installed_package_pages function in optiscope/dash_app/core/page_registry.py will find any installed packages with this entry point and register the pages automatically.
Adding Custom File Formats¶
You can add a new file handler in two ways: by developing it directly within the Optiscope project or by creating an external library that plugs into the application.
Method A: Registering within Optiscope¶
Create a new handler by subclassing BaseFormatHandler and then register it with the global registry:
from optiscope.io import BaseFormatHandler, get_global_registry
class MyFormatHandler(BaseFormatHandler):
format_name = "MyFormat"
file_extensions = [".myformat"]
priority = 15
@classmethod
def can_handle(cls, filepath):
# Detection logic
return filepath.suffix == ".myformat"
def read(self, filepath, **kwargs):
# Read and return OptimizationResult
...
def write(self, result, filepath, **kwargs):
# Write OptimizationResult to file
...
# Register the handler
registry = get_global_registry()
registry.register(MyFormatHandler)
Method B: Creating an External Library (Plugin)¶
This method is ideal for creating extensions or plugins that can be installed as separate Python packages. The file handler is discovered via entry points defined in your library's pyproject.toml.
-
Set up your library structure. It can be structured however you like, but it must contain your
BaseFormatHandlerimplementation. -
Define an entry point in your library's
pyproject.tomlunder theoptiscope.io.handlersgroup. This tells Optiscope where to find your file handler.-[project.entry-points."optiscope.io.handlers"] my_handler_entry_point = "my_plugin.handlers:MyFormatHandler"my_handler_entry_pointis a unique name for your entry point. -my_plugin.handlers:MyFormatHandleris the import path to yourBaseFormatHandlersubclass.
The discover_handlers function in optiscope/io/registry.py will find any installed packages with this entry point and register the handlers automatically.