Skip to content

Commit

Permalink
inspects component init for name and kwargs
Browse files Browse the repository at this point in the history
  • Loading branch information
oegedijk committed Jan 9, 2021
1 parent e74643d commit ad746b2
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 49 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,5 @@ hub.yaml
hub.ipynb
dashboard1.yaml
dashboard2.yaml
users.yaml

55 changes: 51 additions & 4 deletions explainerdashboard/dashboard_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
'get_dbc_tooltips',
'update_params',
'update_kwargs',
'instantiate_component'
]

import sys
Expand Down Expand Up @@ -173,9 +174,12 @@ def __init__(self, explainer, title=None, name=None):
it's unique. Defaults to None.
"""
self._store_child_params(no_param=['explainer'])

if self.name is None:
self.name = shortuuid.ShortUUID().random(length=5)
if not hasattr(self, "name") or self.name is None:
self.name = "uuid"+shortuuid.ShortUUID().random(length=5)
if title is not None:
self.title = title
if not hasattr(self, "title"):
self.title = "Custom"

self._components = []
self._dependencies = []
Expand Down Expand Up @@ -393,4 +397,47 @@ def layout(self):
)
])
else:
return html.Div([dcc.Input(id="pos-label-"+self.name)], style=dict(display="none"))
return html.Div([dcc.Input(id="pos-label-"+self.name)], style=dict(display="none"))


def instantiate_component(component, explainer, name=None, **kwargs):
"""Returns an instantiated ExplainerComponent.
If the component input is just a class definition, instantiate it with
explainer and k**wargs.
If it is already an ExplainerComponent instance then return it.
If it is any other instance with layout and register_components methods,
then add a name property and return it.
Args:
component ([type]): Either a class definition or instance
explainer ([type]): An Explainer object that will be used to instantiate class definitions
name (str): name to assign to ExplainerComponent
kwargs: kwargs will be passed on to the instance
Raises:
ValueError: if component is not a subclass or instance of ExplainerComponent,
or is an instance without layout and register_callbacks methods
Returns:
ExplainerComponent: instantiated component
"""

if inspect.isclass(component) and issubclass(component, ExplainerComponent):
init_argspec = inspect.getargspec(component.__init__)
if not init_argspec.keywords:
kwargs = {k:v for k,v in kwargs.items() if k in init_argspec.args}
if "name" in init_argspec.args:
component = component(explainer, name=name, **kwargs)
else:
print(f"ExplainerComponent {component} does not accept a name parameter, "
f"so cannot assign name={name}!"
"Make sure to set name explicitly yourself if you want to "
"deploy across multiple workers or a cluster, as otherwise "
"each instance in the cluster will generate its own random "
"uuid name!")
component = component(explainer, **kwargs)
return component
elif isinstance(component, ExplainerComponent):
return component
else:
raise ValueError(f"{component} is not a valid ExplainerComponent...")
45 changes: 1 addition & 44 deletions explainerdashboard/dashboards.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,54 +34,12 @@

import plotly.io as pio

from .dashboard_methods import instantiate_component
from .dashboard_components import *
from .dashboard_tabs import *
from .explainers import BaseExplainer




def instantiate_component(component, explainer, name=None, **kwargs):
"""Returns an instantiated ExplainerComponent.
If the component input is just a class definition, instantiate it with
explainer and k**wargs.
If it is already an ExplainerComponent instance then return it.
If it is any other instance with layout and register_components methods,
then add a name property and return it.
Args:
component ([type]): Either a class definition or instance
explainer ([type]): An Explainer object that will be used to instantiate class definitions
kwargs: kwargs will be passed on to the instance
Raises:
ValueError: if component is not a subclass or instance of ExplainerComponent,
or is an instance without layout and register_callbacks methods
Returns:
[type]: instantiated component
"""

if inspect.isclass(component) and issubclass(component, ExplainerComponent):
component = component(explainer, name=name, **kwargs)
return component
elif isinstance(component, ExplainerComponent):
return component
elif (not inspect.isclass(component)
and hasattr(component, "layout")):
if not (hasattr(component, "name") and isinstance(component.name, str)):
if name is None:
name = shortuuid.ShortUUID().random(length=5)
print(f"Warning: setting {component}.name to {name}")
component.name = name
if not hasattr(component, "title"):
print(f"Warning: setting {component}.title to 'Custom'")
component.title = "Custom"
return component
else:
raise ValueError(f"{component} is not a valid component...")


class ExplainerTabsLayout:
def __init__(self, explainer, tabs,
title='Model Explainer',
Expand Down Expand Up @@ -234,7 +192,6 @@ class definition or instance.

self.selector = PosLabelSelector(explainer, name="0", pos_label=pos_label)
self.page = instantiate_component(component, explainer, name="1", **kwargs)
print(self.page.name, flush=True)
self.connector = PosLabelConnector(self.selector, self.page)

self.fluid = fluid
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name='explainerdashboard',
version='0.2.19',
version='0.2.19.1',
description='explainerdashboard allows you quickly build an interactive dashboard to explain the inner workings of your machine learning model.',
long_description="""
Expand Down

0 comments on commit ad746b2

Please sign in to comment.