Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Variables to reference each other #259

Merged
merged 1 commit into from
Mar 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions lumen/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,7 @@ def __init__(self, specification=None, **params):
self.auth = Auth.from_spec(state.spec.get('auth', {}))
self.config = Config.from_spec(state.spec.get('config', {}))
self.defaults = Defaults.from_spec(state.spec.get('defaults', {}))
vars = Variables.from_spec(state.spec.get('variables', {}))
self.variables = state._variables[pn.state.curdoc] = vars
self.variables = Variables.from_spec(state.spec.get('variables', {}))
self.defaults.apply()

# Load and populate template
Expand Down
6 changes: 5 additions & 1 deletion lumen/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,14 @@ def _resolve_source_ref(self, refs):
def resolve_reference(self, reference, variables=None):
if not is_ref(reference):
raise ValueError('References should be prefixed by $ symbol.')
from .variables import Variable
refs = reference[1:].split('.')
vars = variables or self.variables
if refs[0] == 'variables':
return vars[refs[1]]
value = vars[refs[1]]
if isinstance(value, Variable):
value = value.value
return value
return self._resolve_source_ref(refs)


Expand Down
2 changes: 1 addition & 1 deletion lumen/ui/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def _yaml_upload(self, event):
return

def _create_new(self, event):
self.spec = {'config': {}, 'sources': {}, 'targets': []}
self.spec = {'config': {}, 'sources': {}, 'targets': [], 'variables': {}}

def _selected(self, event):
self.spec = event.obj.spec
61 changes: 42 additions & 19 deletions lumen/variables/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,48 @@


class Variables(param.Parameterized):
"""
The Variables component stores a number Variable types and mirrors
their values onto dynamically created parameters allowing other
components to easily watch changes in a variable.
"""

def __init__(self, **vars):
super().__init__()
for p, var in vars.items():
vtype = type(var.value)
ptype = _PARAM_MAP.get(vtype, param.Parameter)
self.param.add_parameter(p, ptype())
var.param.watch(partial(self._update_value, p), 'value')
var.param.trigger('value')
self._vars = vars

def _update_value(self, p, event):
self.param.update({p: event.new})

def __getitem__(self, key):
return getattr(self, key)
def __init__(self, **params):
super().__init__(**params)
self._vars = {}

@classmethod
def from_spec(cls, spec):
vars = {}
variables = cls()
if pn.state.curdoc:
state._variables[pn.state.curdoc] = variables
for name, var_spec in spec.items():
if not isinstance(var_spec, dict):
var_spec = {
'type': 'constant',
'default': var_spec
}
vars[name] = Variable.from_spec(dict(var_spec, name=name), vars)
return cls(**vars)
var = Variable.from_spec(dict(var_spec, name=name), variables)
variables.add_variable(var)
return variables

def add_variable(self, var):
"""
Adds a new variable to the Variables instance and sets up
a parameter that can be watched.
"""
self._vars[var.name] = var
self.param.add_parameter(var.name, param.Parameter(default=var.value))
var.param.watch(partial(self._update_value, var.name), 'value')

def _update_value(self, name, event):
self.param.update({name: event.new})

def __getitem__(self, key):
if key in self.param:
return getattr(self, key)
else:
raise KeyError(f'No variable named {key!r} has been defined.')

@property
def panel(self):
Expand All @@ -60,6 +74,14 @@ def panel(self):


class Variable(Component):
"""
A Variable may declare a static or dynamic value that can be
referenced from other components. The source of the Variable value
can be anything from an environment variable to a widget or URL
parameter. Variable components allow a concise way to configure
other components and make it possible to orchestrate actions across
multiple components.
"""

default = param.Parameter(doc="""
Default value to use if no other value is defined""")
Expand All @@ -74,7 +96,8 @@ class Variable(Component):
secure = param.Boolean(default=False, constant=True, doc="""
Whether the variable should be treated as secure.""")

value = param.Parameter()
value = param.Parameter(doc="""
The materialized value of the variable.""")

variable_type = None

Expand Down