actions
ActionInputs
from dara.core.interactivity.actions import ActionInputs
class ActionInputs(BaseModel)
Base class for all action inputs
ActionContext
from dara.core.interactivity.actions import ActionContext
class ActionContext(BaseModel)
Base class for action context
@deprecated: used in deprecated action wrappers
Attributes
- extras: List[Any]
- inputs: ActionInputs
ComponentActionContext
from dara.core.interactivity.actions import ComponentActionContext
class ComponentActionContext(ActionContext)
ActionContext for actions that only require component value
Attributes
- inputs: ComponentActionInputs
UpdateVariableImpl
from dara.core.interactivity.actions import UpdateVariableImpl
class UpdateVariableImpl(ActionImpl)
Update a given variable to provided value. Can be used standalone for updating to static values.
For more complex cases use the @action decorator and the ctx.update method on the injected context.
from dara.core import Variable, UpdateVariableImpl
from dara.components import Button
my_var = Variable(0)
Button(
'UpdateVariable',
onclick=UpdateVariableImpl(my_var, 5),
)
Arguments:
variable: the variable to updatevalue: the new value for the variable
Attributes
- variable: Union[Variable, UrlVariable, DataVariable]
- value: Any
- INPUT: ClassVar[str]
- TOGGLE: ClassVar[str]
INPUT
Special value for value that will be replaced with the input value
TOGGLE
Special value for value that will toggle the variable value
UpdateVariable
from dara.core.interactivity.actions import UpdateVariable
@deprecated('Use @action or `UpdateVariableImpl` for simple cases')
class UpdateVariable(AnnotatedAction)
@deprecated: Passing in resolvers is deprecated, use ctx.update in an @action or UpdateVariableImpl instead.
UpdateVariableImpl will be renamed to UpdateVariable in Dara 2.0.
The UpdateVariable action can be passed to any ComponentInstance prop accepting an action and trigger the update of a Variable, UrlVariable or DataVariable.
The resolver function takes a Context param which will feed the inputs: old and new as well as any extras passed through.
Below an example of how a resolver might look:
from dara.core import Variable, UpdateVariable
from dara.components import Button
my_var = Variable(0)
x = Variable(1)
y = Variable(2)
z = Variable(3)
def my_resolver(ctx: UpdateVariable.Ctx):
# The UpdateVariable action has two inputs predefined, old, which is the value of
# the variable before update, and new which would have for example the selected value
# of a `Select` component.
old = ctx.inputs.old
new = ctx.inputs.new
# The resolved values of any extras passed are returned as a list
x, y, z = ctx.extras
return old + x + y * z
Button(
'UpdateVariable',
onclick=UpdateVariable(variable=my_var, resolver=my_resolver, extras=[x,y,z]),
)
Example of how you could use UpdateVariable to toggle between true and false:
from dara.core import Variable, UpdateVariable
from dara.components import Button
var = Variable(True)
Button(
'Toggle',
onclick=UpdateVariable(variable=var, resolver=lambda ctx: not ctx.inputs.old),
)
Example of using UpdateVariable to sync values:
from dara.core import Variable, UpdateVariable
from dara.components import Select
var = Variable('first')
Select(
value=Variable('first'),
items=['first', 'second', 'third'],
onchange=UpdateVariable(lambda ctx: ctx.inputs.new, var),
)
Attributes
- Ctx: ClassVar[type[UpdateVariableContext]]
- variable: Union[Variable, DataVariable, UrlVariable]
- extras: Optional[List[AnyVariable]]
Methods
__init__
def __init__(resolver: Callable[[UpdateVariableContext], Any],
variable: Union[Variable, DataVariable, UrlVariable],
extras: Optional[List[AnyVariable]] = None)
Arguments:
resolver: a function to resolve the new value for the variable. Takes one arguments: containing a context of typeUpdatevariable.Ctxvariable: the variable or url variable to update with a new value upon triggering the actionextras: any extra variables to resolve and pass to the resolution function context
TriggerVariable
from dara.core.interactivity.actions import TriggerVariable
class TriggerVariable(ActionImpl)
Force a recalculation of a DerivedVariable.
from dara.core import action, ConfigurationBuilder, Variable, DerivedVariable, TriggerVariable
from dara.components import Stack, Button, Text
config = ConfigurationBuilder()
var1 = Variable(1)
var2 = Variable(2)
der_var = DerivedVariable(lambda x, y: x + y, variables=[var1, var2], deps=[var2])
@action
async def update(ctx: action.Ctx, previous_value: int):
await ctx.update(var_1, previous_value + 1)
def test_page():
return Stack(
# When clicking this button der_var syncs and calculates latest sum value
Button('Trigger der_var', onclick=TriggerVariable(variable=der_var)),
# Because var1 is not a deps of der_var changing its value does not trigger an update
Button('Add 1 to var1', onclick=update(var_1)),
Stack(Text('der_var: '), Text(der_var), direction='horizontal'),
Stack(Text('var1: '), Text(var1), direction='horizontal'),
Stack(Text('var2: '), Text(var2), direction='horizontal'),
)
config.add_page(name='Trigger Variable', content=test_page())
Attributes
- variable: DerivedVariable
- force: bool
NavigateToImpl
from dara.core.interactivity.actions import NavigateToImpl
class NavigateToImpl(ActionImpl)
Navigate to a given url.
Basic example of how to use NavigateToImpl:
from dara.core import NavigateToImpl, Variable, ConfigurationBuilder
from dara.components import Stack, Button, Select
config = ConfigurationBuilder()
def test_page():
return Stack(
# open in the same tab
Button('Go to Another Page', onclick=NavigateToImpl(url='/another-page')),
)
def another_page():
return Stack(
# open in a new tab
Button('Go to Another Page', onclick=NavigateToImpl(url='/test-page', new_tab=True)),
)
config.add_page(name='Test Page', content=test_page())
config.add_page(name='Another Page', content=another_page())
Attributes
- url: Optional[str]
- new_tab: bool
NavigateTo
@deprecated('Use @action or `NavigateToImpl` for simple cases')
def NavigateTo(url: Union[str, Callable[[Any], str]],
new_tab: bool = False,
extras: Optional[List[AnyVariable]] = None)
@deprecated: Passing in resolvers is deprecated, use ctx.navigate in an @action or NavigateToImpl instead.
The NavigateTo action can be passed to any ComponentInstance prop accepting an ActionInstance and will trigger a change in route
based on the url passed. The url can be a static string, or it can be a function that will be called with the
element that triggered the action (the structure of this will depend on the component this action is passed to).
Basic example of how to use NavigateTo:
from dara.core import NavigateTo, Variable
from dara.core.configuration import ConfigurationBuilder
from dara.core.css import get_icon
from dara.components import Stack, Button, Select
config = ConfigurationBuilder()
def test_page():
return Stack(
# passing url as a static string
Button('Go to Another Page', onclick=NavigateTo('/another-page')),
)
def another_page():
# passing url as a function based on component value
return Stack(
Select(
value=Variable('/test-page'),
items=['/test-page', '/another-page', 'https://www.google.com/'],
onchange=NavigateTo(lambda ctx: ctx.inputs.value),
)
)
config.add_page(name='Test Page', content=test_page(), icon=get_icon('shield-dog'))
config.add_page(name='Another Page', content=another_page(), icon=get_icon('shield-cat'))
Logout
def Logout()
Logout action, this triggers the UI to logout the user
Example of adding Logout action to a button:
from dara.core import ConfigurationBuilder, Logout
from dara.core.auth import BasicAuthConfig
from dara.components import Stack, Button
config = ConfigurationBuilder()
config.add_auth(BasicAuthConfig(username='test', password='test'))
def test_page():
return Stack(Button('Logout', onclick=Logout()))
config.add_page(name='Logout Page', content=test_page())
ResetVariables
from dara.core.interactivity.actions import ResetVariables
class ResetVariables(ActionImpl)
Reset a number of variables to their default values
Basic example of resetting a Variable:
from dara.core import Variable, ResetVariables, UpdateVariable
from dara.core.configuration import ConfigurationBuilder
from dara.core.css import get_icon
from dara.components import Stack, Button, Text
config = ConfigurationBuilder()
my_var = Variable(0)
def test_page():
return Stack(
Text(my_var),
# when clicked, 1 is added to my_var
Button('Add', onclick=UpdateVariable(lambda ctx: ctx.inputs.old + 1, my_var)),
# when clicked my_var goes back to its initial value: 0
Button('Reset', onclick=ResetVariables(variables=[my_var])),
)
config.add_page(name='ResetVariable', content=test_page(), icon=get_icon('shrimp'))
Arguments:
variables: list of variables to reset
Attributes
- variables: List[AnyVariable]
Notify
from dara.core.interactivity.actions import Notify
class Notify(ActionImpl)
Notify action, this triggers the UI to create a notification which is presented to the user, with a title and message.
from dara.core import Notify, ConfigurationBuilder
from dara.components import Stack, Button
config = ConfigurationBuilder()
def test_page():
return Stack(
Button(
'Notify',
onclick=Notify(
message='This is the notification message', title='Example', status=Notify.Status.SUCCESS
),
)
)
config.add_page(name='Notify Example', content=test_page())
Attributes
- key: Optional[str]
- message: str
- status: NotificationStatus
- title: str
- Status: ClassVar[type[NotificationStatus]]
- Ctx: ClassVar[type[ComponentActionContext]]
Ctx
@deprecated retained for backwards compatibility, to be removed in 2.0
DownloadContentImpl
from dara.core.interactivity.actions import DownloadContentImpl
class DownloadContentImpl(ActionImpl)
Download action, downloads a given file
from dara.core import ConfigurationBuilder, DownloadContentImpl
from dara.components.components import Button, Stack
config = ConfigurationBuilder()
def test_page():
return Stack(
Button(
'Download File', onclick=DownloadContentImpl(path='/path/to/file', cleanup_file=False)
),
)
config.add_page(name='Download Content', content=test_page)
Attributes
- code: str
DownloadContent
@deprecated('Use @action instead')
def DownloadContent(resolver: Callable[[ComponentActionContext], str],
extras: Optional[List[AnyVariable]] = None,
cleanup_file: bool = False)
@deprecated This action is deprecated, use ctx.download_file in an @action instead.
Download action, downloads a given file
from dara.core import action, ConfigurationBuilder, DataVariable, DownloadContent
from dara.components.components import Button, Stack
# generate data, alternatively you could load it from a file
df = pandas.DataFrame(data={'x': [1, 2, 3], 'y':[4, 5, 6]})
my_var = DataVariable(df)
config = ConfigurationBuilder()
def return_csv(ctx: DownloadContent.Ctx) -> str:
# The file can be created and saved dynamically here, it should then return a string with a path to it
# To get the component value, e.g. a select component would return the selected value
component_value = ctx.inputs.value
# Getting the value of data passed as extras to the action
data = ctx.extras[0]
# save the data to csv
data.to_csv('<PATH_TO_CSV.csv>')
return '<PATH_TO_CSV.csv>'
def test_page():
return Stack(
Button(
'Download File', onclick=DownloadContent(resolver=return_csv, extras=[my_var], cleanup_file=False)
),
)
config.add_page(name='Download Content', content=test_page)
DownloadContent.Ctx
@deprecated retained for backwards compatibility, to be removed in 2.0
DownloadVariable
from dara.core.interactivity.actions import DownloadVariable
class DownloadVariable(ActionImpl)
Download action, downloads the content of a given variable as a file.
Note that as of now variables ran as a task are not supported.
from dara.core import ConfigurationBuilder, DownloadVariable, Variable
from dara.components import Stack, Button
config = ConfigurationBuilder()
my_var = Variable({'foo': 'bar'})
def test_page():
return Stack(
Button(
'Download Variable',
onclick=DownloadVariable(variable=my_var, file_name='test_file', type='json'),
)
)
config.add_page(name='Download Variable', content=test_page())
Attributes
- variable: AnyVariable
- file_name: Optional[str]
- type: Literal[]
SideEffect
@deprecated('Use @action instead')
def SideEffect(function: Callable[[ComponentActionContext], Any],
extras: Optional[List[AnyVariable]] = None,
block: bool = False)
@deprecated: This action is deprecated, use @action instead.
The SideEffect action can be passed to any ComponentInstance prop accepting an ActionInstance in order to trigger an arbitrary python function
Example of how to get values from context in SideEffect function:
from dara.core import Variable, SideEffect
from dara.core.configuration import ConfigurationBuilder
from dara.core.css import get_icon
from dara.components import Stack, Select
config = ConfigurationBuilder()
x = Variable(0)
y = Variable(1)
z = Variable(2)
def side_effect(ctx: SideEffect.Ctx):
value = ctx.inputs.value
x, y, z = ctx.extras
print('value:', value)
print(f'x:{x}, y:{y}, z:{z}')
def test_page():
return Stack(Select(value=Variable(3), items=[3, 4, 5], onchange=SideEffect(side_effect, extras=[x, y, z])))
config.add_page(name='SideEffect', content=test_page(), icon=get_icon('kiwi-bird'))
SideEffect.Ctx
@deprecated retained for backwards compatibility, to be removed in 2.0
ActionCtx
from dara.core.interactivity.actions import ActionCtx
class ActionCtx()
Action execution context passed to an @action-annotated action when it is being executed.
Exposes input, the input value passed to the action by the invoking components,
and an collection of methods for interacting with the frontend.
Attributes
- _action_send_stream: MemoryObjectSendStream[ActionImpl]
- _action_receive_stream: MemoryObjectReceiveStream[ActionImpl]
- _on_action: Callable[[Optional[ActionImpl]], Awaitable]
- input: Any
Methods
update
async def update(variable: Union[Variable, UrlVariable, DataVariable],
value: Any)
Update a given variable to provided value.
from dara.core import action, Variable
from dara.components import Button
my_var = Variable(0)
x = Variable(1)
y = Variable(2)
z = Variable(3)
**Arguments**:
- `variable`: the variable to update
:param value: the new value for the variable
#### trigger
```python
async def trigger(variable: DerivedVariable, force: bool = True)
Trigger a given DerivedVariable to recalculate.
from dara.core import action, ConfigurationBuilder, Variable, DerivedVariable
from dara.core.configuration import ConfigurationBuilder
from dara.components import Stack, Button, Text
config = ConfigurationBuilder()
var1 = Variable(1)
var2 = Variable(2)
der_var = DerivedVariable(lambda x, y: x + y, variables=[var1, var2], deps=[var2])
@action
async def update(ctx: action.Ctx, previous_value: int):
await ctx.update(var_1, previous_value + 1)
@action
async def trigger(ctx: action.Ctx):
await ctx.trigger(der_var)
def test_page():
return Stack(
# When clicking this button der_var syncs and calculates latest sum value
Button('Trigger der_var', onclick=trigger()),
# Because var1 is not a deps of der_var changing its value does not trigger an update
Button('Add 1 to var1', onclick=update(var_1)),
Stack(Text('der_var: '), Text(der_var), direction='horizontal'),
Stack(Text('var1: '), Text(var1), direction='horizontal'),
Stack(Text('var2: '), Text(var2), direction='horizontal'),
)
config.add_page(name='Trigger Variable', content=test_page())
Arguments:
variable: the variable to triggerforce: whether to force the recalculation, defaults to True
navigate
async def navigate(url: str, new_tab: bool = False)
Navigate to a given url
from dara.core import action, ConfigurationBuilder, Variable
from dara.components import Stack, Button, Select
config = ConfigurationBuilder()
@action
async def navigate_to(ctx: action.Ctx, url: str):
# Navigate to the url provided
await ctx.navigate(url)
def test_page():
return Stack(
Button('Go to Another Page', onclick=navigate_to('/another-page')),
)
@action
async def navigate_to_input(ctx: action.Ctx):
# Navigate to the value of the input provided to the action
await ctx.navigate(ctx.input)
def another_page():
return Stack(
Select(
value=Variable('/test-page'),
items=['/test-page', '/another-page', 'https://www.google.com/'],
onchange=navigate_to_input(),
)
)
config.add_page(name='Test Page', content=test_page())
config.add_page(name='Another Page', content=another_page())
Arguments:
url: the url to navigate tonew_tab: whether to open the url in a new tab, defaults to False
logout
async def logout()
Logout the current user.
from dara.core import ConfigurationBuilder, action
from dara.core.auth import BasicAuthConfig
from dara.components import Stack, Button
config = ConfigurationBuilder()
config.add_auth(BasicAuthConfig(username='test', password='test'))
@action
async def logout(ctx: action.Ctx):
await ctx.logout()
def test_page():
return Stack(Button('Logout', onclick=logout()))
config.add_page(name='Logout Page', content=test_page())
notify
async def notify(message: str,
title: str,
status: Union[NotificationStatus, NotificationStatusString],
key: Optional[str] = None)
Display a notification toast on the frontend
from dara.core import action, ConfigurationBuilder
from dara.components import Stack, Button
config = ConfigurationBuilder()
@action
async def notify(ctx: action.Ctx):
await ctx.notify(
message='This is the notification message', title='Example', status='SUCCESS'
)
def test_page():
return Stack(
Button(
'Notify',
onclick=notify()
)
)
config.add_page(name='Notify Example', content=test_page())
Arguments:
message: the message to displaytitle: the title of the notificationstatus: the status of the notificationkey: optional key for the notification
reset_variables
async def reset_variables(variables: Union[List[AnyVariable], AnyVariable])
Reset a list of variables to their default values.
from dara.core import Variable, action, ConfigurationBuilder
from dara.components import Stack, Button, Text
config = ConfigurationBuilder()
my_var = Variable(0)
**Arguments**:
- `variables`: a variable or list of variables to reset
#### download\_file
```python
async def download_file(path: str, cleanup: bool = False)
Download a given file.
from dara.core import action, ConfigurationBuilder, DataVariable
from dara.components.components import Button, Stack
# generate data, alternatively you could load it from a file
df = pandas.DataFrame(data={'x': [1, 2, 3], 'y':[4, 5, 6]})
my_var = DataVariable(df)
config = ConfigurationBuilder()
@action
async def download_csv(ctx: action.Ctx, my_var_value: DataFrame) -> str:
# Getting the value of data passed as extras to the action
data = my_var_value
# save the data to csv
data.to_csv('<PATH_TO_CSV.csv>')
# Instruct the frontend to download the file and clean up afterwards
await ctx.download_file(path='<PATH_TO_CSV.csv>', cleanup=True)
def test_page():
return Stack(
Button(
'Download File', onclick=download_csv(my_var)
),
)
config.add_page(name='Download Content', content=test_page)
Arguments:
path: the path to the file to downloadcleanup: whether to delete the file after download
download_variable
async def download_variable(variable: AnyVariable,
file_name: Optional[str] = None,
type: Literal['csv', 'xlsx', 'json'] = 'csv')
Download the content of a given variable as a file.
Note that the content of the file must be valid for the given type.
from dara.core import action, ConfigurationBuilder, Variable
from dara.components import Stack, Button
config = ConfigurationBuilder()
my_var = Variable({'foo': 'bar'})
@action
async def download(ctx: action.Ctx):
await ctx.download_variable(variable=my_var, file_name='test_file', type='json')
def test_page():
return Stack(
Button(
'Download Variable',
onclick=download(),
)
)
config.add_page(name='Download Variable', content=test_page())
Arguments:
variable: the variable to downloadfile_name: optional name of the file to downloadtype: the type of the file to download, defaults to csv
run_task
async def run_task(
func: Callable,
args: Union[List[Any], None] = None,
kwargs: Union[Dict[str, Any], None] = None,
on_progress: Optional[Callable[[TaskProgressUpdate],
Union[None, Awaitable[None]]]] = None)
Run a calculation as a task in a separate process. Recommended for CPU intensive tasks.
Returns the result of the task function.
Note that the function must be defined in a separate module as configured in task_module field of the
configuration builder. This is because Dara spawns separate worker processes only designed to run
functions from that designated module.
from dara.core import ConfigurationBuilder, TaskProgressUpdate, action, ActionCtx, Variable
from dara.components import Text, Stack, Button
from .my_module import my_task_function
config = ConfigurationBuilder()
config.task_module = 'my_module'
status = Variable('Not started')
@action
async def my_task(ctx: ActionCtx):
async def on_progress(update: TaskProgressUpdate):
await ctx.update(status, f'Progress: {update.progress}% - {update.message}')
try:
result = await ctx.run_task(my_task_function, args=[1, 10], on_progress=on_progress)
await ctx.update(status, f'Result: {result}')
except Exception as e:
await ctx.update(status, f'Error: {e}')
def task_page():
return Stack(Text('Status display:'), Text(text=status), Button('Run', onclick=my_task()))
config.add_page(name='task', content=task_page())
Arguments:
func: the function to run as a taskargs: the arguments to pass to the functionkwargs: the keyword arguments to pass to the functionon_progress: a callback to receive progress updates
execute_action
async def execute_action(action: ActionImpl)
Execute a given action.
Arguments:
action: the action impl instance to execute
ACTION_CONTEXT
Current execution context
assert_no_context
def assert_no_context(alternative: str)
Assert that no action context is active.
This is used to ensure shortcut actions are not used within an @action as they are synchronous and return a simple object, while to execute it once needs to await its execution.
action
from dara.core.interactivity.actions import action
class action()
A decorator for creating actions. Actions are used to trigger changes in the UI, such as updating a variable, navigating to a new page, etc.
The decorator injects an ActionCtx object as the first argument to the decorated function, which can be used to access the available
actions as well as the input value of the component that triggered the action. Note that the context methods are asynchronous,
so the decorated function must be async to use them.
An @action-decorated function can be called with a list of Variable and non-Variable arguments. The non-Variable arguments will be passed as-is to the decorated function, while the Variable arguments will be passed as the current value of the Variable.
from dara.core import action, Variable
from dara.components import Select, Item
some_variable = Variable(1)
other_variable = Variable(2)
@action
async def my_action(ctx: action.Ctx, arg_1: int, arg_2: int):
# Value coming from the component, in this case the selected item
value = ctx.input
# Your action logic...
# Update `some_variable` to `value` multiplied by arg_1 and arg_2
await ctx.update(variable=some_variable, value=value * arg_1 * arg_2)
Select(
items=[Item(label='item1', value=1), Item(label='item2', value=2)],
onchange=my_action(2, other_variable)
)
Attributes
- Ctx: ClassVar[type[ActionCtx]]
Methods
__get__
def __get__(instance: Any, owner=None) -> Callable[..., Any]
Get descriptor for the decorated function.
Necessary to support instance/class bound methods.