This commit is contained in:
2025-09-07 22:09:54 +02:00
parent e1b817252c
commit 2fc0d000b6
7796 changed files with 2159515 additions and 933 deletions
@@ -0,0 +1,97 @@
# pylint: disable=C0413
# __plotly_dash is for the "make sure you don't have a dash.py" check
# must come before any other imports.
__plotly_dash = True
from .dependencies import ( # noqa: F401,E402
Input, # noqa: F401,E402
Output, # noqa: F401,E402,
State, # noqa: F401,E402
ClientsideFunction, # noqa: F401,E402
MATCH, # noqa: F401,E402
ALL, # noqa: F401,E402
ALLSMALLER, # noqa: F401,E402
) # noqa: F401,E402
from . import development # noqa: F401,E402
from . import exceptions # noqa: F401,E402
from . import resources # noqa: F401,E402
from . import dcc # noqa: F401,E402
from . import html # noqa: F401,E402
from . import dash_table # noqa: F401,E402
from .version import __version__ # noqa: F401,E402
from ._callback_context import callback_context, set_props # noqa: F401,E402
from ._callback import callback, clientside_callback # noqa: F401,E402
from ._get_app import get_app # noqa: F401,E402
from ._get_paths import ( # noqa: F401,E402
get_asset_url,
get_relative_path,
strip_relative_path,
)
from ._no_update import NoUpdate # noqa: F401,E402
from .background_callback import ( # noqa: F401,E402
CeleryManager,
DiskcacheManager,
)
from ._utils import stringify_id # noqa: F401,E402
from ._pages import register_page, PAGE_REGISTRY as page_registry # noqa: F401,E402
from .dash import ( # noqa: F401,E402
Dash,
no_update,
page_container,
)
from ._patch import Patch # noqa: F401,E402
from ._jupyter import jupyter_dash # noqa: F401,E402
from ._hooks import hooks # noqa: F401,E402
ctx = callback_context
def _jupyter_nbextension_paths():
return [
{
"section": "notebook",
"src": "nbextension",
"dest": "dash",
"require": "dash/main",
}
]
__all__ = [
"Input",
"Output",
"State",
"clientside_callback",
"ClientsideFunction",
"MATCH",
"ALLSMALLER",
"ALL",
"development",
"exceptions",
"dcc",
"html",
"dash_table",
"__version__",
"callback_context",
"set_props",
"callback",
"get_app",
"get_asset_url",
"get_relative_path",
"strip_relative_path",
"CeleryManager",
"DiskcacheManager",
"register_page",
"page_registry",
"Dash",
"no_update",
"NoUpdate",
"page_container",
"Patch",
"jupyter_dash",
"ctx",
"hooks",
"stringify_id",
]
@@ -0,0 +1,850 @@
import collections
import hashlib
from functools import wraps
from typing import Callable, Optional, Any, List, Tuple, Union
import asyncio
import flask
from .dependencies import (
handle_callback_args,
handle_grouped_callback_args,
Output,
ClientsideFunction,
Input,
)
from .development.base_component import ComponentRegistry
from .exceptions import (
InvalidCallbackReturnValue,
PreventUpdate,
WildcardInLongCallback,
MissingLongCallbackManagerError,
BackgroundCallbackError,
ImportedInsideCallbackError,
)
from ._grouping import (
flatten_grouping,
make_grouping_by_index,
grouping_len,
)
from ._utils import (
create_callback_id,
stringify_id,
to_json,
coerce_to_list,
AttributeDict,
clean_property_name,
)
from . import _validate
from .background_callback.managers import BaseBackgroundCallbackManager
from ._callback_context import context_value
from ._no_update import NoUpdate
async def _async_invoke_callback(
func, *args, **kwargs
): # used to mark the frame for the debugger
# Check if the function is a coroutine function
if asyncio.iscoroutinefunction(func):
return await func(*args, **kwargs) # %% callback invoked %%
# If the function is not a coroutine, call it directly
return func(*args, **kwargs) # %% callback invoked %%
def _invoke_callback(func, *args, **kwargs): # used to mark the frame for the debugger
return func(*args, **kwargs) # %% callback invoked %%
GLOBAL_CALLBACK_LIST = []
GLOBAL_CALLBACK_MAP = {}
GLOBAL_INLINE_SCRIPTS = []
# pylint: disable=too-many-locals
def callback(
*_args,
background: bool = False,
interval: int = 1000,
progress: Optional[Union[List[Output], Output]] = None,
progress_default: Any = None,
running: Optional[List[Tuple[Output, Any, Any]]] = None,
cancel: Optional[Union[List[Input], Input]] = None,
manager: Optional[BaseBackgroundCallbackManager] = None,
cache_args_to_ignore: Optional[list] = None,
cache_ignore_triggered=True,
on_error: Optional[Callable[[Exception], Any]] = None,
**_kwargs,
) -> Callable[..., Any]:
"""
Normally used as a decorator, `@dash.callback` provides a server-side
callback relating the values of one or more `Output` items to one or
more `Input` items which will trigger the callback when they change,
and optionally `State` items which provide additional information but
do not trigger the callback directly.
`@dash.callback` is an alternative to `@app.callback` (where `app = dash.Dash()`)
introduced in Dash 2.0.
It allows you to register callbacks without defining or importing the `app`
object. The call signature is identical and it can be used instead of `app.callback`
in all cases.
The last, optional argument `prevent_initial_call` causes the callback
not to fire when its outputs are first added to the page. Defaults to
`False` and unlike `app.callback` is not configurable at the app level.
:Keyword Arguments:
:param background:
Mark the callback as a background callback to execute in a manager for
callbacks that take a long time without locking up the Dash app
or timing out.
:param manager:
A background callback manager instance. Currently, an instance of one of
`DiskcacheManager` or `CeleryManager`.
Defaults to the `background_callback_manager` instance provided to the
`dash.Dash constructor`.
- A diskcache manager (`DiskcacheManager`) that runs callback
logic in a separate process and stores the results to disk using the
diskcache library. This is the easiest backend to use for local
development.
- A Celery manager (`CeleryManager`) that runs callback logic
in a celery worker and returns results to the Dash app through a Celery
broker like RabbitMQ or Redis.
:param running:
A list of 3-element tuples. The first element of each tuple should be
an `Output` dependency object referencing a property of a component in
the app layout. The second element is the value that the property
should be set to while the callback is running, and the third element
is the value the property should be set to when the callback completes.
:param cancel:
A list of `Input` dependency objects that reference a property of a
component in the app's layout. When the value of this property changes
while a callback is running, the callback is canceled.
Note that the value of the property is not significant, any change in
value will result in the cancellation of the running job (if any).
This parameter only applies to background callbacks (`background=True`).
:param progress:
An `Output` dependency grouping that references properties of
components in the app's layout. When provided, the decorated function
will be called with an extra argument as the first argument to the
function. This argument, is a function handle that the decorated
function should call in order to provide updates to the app on its
current progress. This function accepts a single argument, which
correspond to the grouping of properties specified in the provided
`Output` dependency grouping. This parameter only applies to background
callbacks (`background=True`).
:param progress_default:
A grouping of values that should be assigned to the components
specified by the `progress` argument when the callback is not in
progress. If `progress_default` is not provided, all the dependency
properties specified in `progress` will be set to `None` when the
callback is not running. This parameter only applies to background
callbacks (`background=True`).
:param cache_args_to_ignore:
Arguments to ignore when caching is enabled. If callback is configured
with keyword arguments (Input/State provided in a dict),
this should be a list of argument names as strings. Otherwise,
this should be a list of argument indices as integers.
This parameter only applies to background callbacks (`background=True`).
:param cache_ignore_triggered:
Whether to ignore which inputs triggered the callback when creating
the cache. This parameter only applies to background callbacks
(`background=True`).
:param interval:
Time to wait between the background callback update requests.
:param on_error:
Function to call when the callback raises an exception. Receives the
exception object as first argument. The callback_context can be used
to access the original callback inputs, states and output.
"""
background_spec = None
config_prevent_initial_callbacks = _kwargs.pop(
"config_prevent_initial_callbacks", False
)
callback_map = _kwargs.pop("callback_map", GLOBAL_CALLBACK_MAP)
callback_list = _kwargs.pop("callback_list", GLOBAL_CALLBACK_LIST)
if background:
background_spec: Any = {
"interval": interval,
}
if manager:
background_spec["manager"] = manager
if progress:
background_spec["progress"] = coerce_to_list(progress)
validate_background_inputs(background_spec["progress"])
if progress_default:
background_spec["progressDefault"] = coerce_to_list(progress_default)
if not len(background_spec["progress"]) == len(
background_spec["progressDefault"]
):
raise Exception(
"Progress and progress default needs to be of same length"
)
if cancel:
cancel_inputs = coerce_to_list(cancel)
validate_background_inputs(cancel_inputs)
background_spec["cancel"] = [c.to_dict() for c in cancel_inputs]
background_spec["cancel_inputs"] = cancel_inputs
if cache_args_to_ignore:
background_spec["cache_args_to_ignore"] = cache_args_to_ignore
background_spec["cache_ignore_triggered"] = cache_ignore_triggered
return register_callback(
callback_list,
callback_map,
config_prevent_initial_callbacks,
*_args,
**_kwargs,
background=background_spec,
manager=manager,
running=running,
on_error=on_error,
)
def validate_background_inputs(deps):
for dep in deps:
if dep.has_wildcard():
raise WildcardInLongCallback(
f"""
background callbacks does not support dependencies with
pattern-matching ids
Received: {repr(dep)}\n"""
)
ClientsideFuncType = Union[str, ClientsideFunction]
def clientside_callback(clientside_function: ClientsideFuncType, *args, **kwargs):
return register_clientside_callback(
GLOBAL_CALLBACK_LIST,
GLOBAL_CALLBACK_MAP,
False,
GLOBAL_INLINE_SCRIPTS,
clientside_function,
*args,
**kwargs,
)
# pylint: disable=too-many-arguments
def insert_callback(
callback_list,
callback_map,
config_prevent_initial_callbacks,
output,
outputs_indices,
inputs,
state,
inputs_state_indices,
prevent_initial_call,
background=None,
manager=None,
running=None,
dynamic_creator: Optional[bool] = False,
no_output=False,
):
if prevent_initial_call is None:
prevent_initial_call = config_prevent_initial_callbacks
_validate.validate_duplicate_output(
output, prevent_initial_call, config_prevent_initial_callbacks
)
callback_id = create_callback_id(output, inputs, no_output)
callback_spec = {
"output": callback_id,
"inputs": [c.to_dict() for c in inputs],
"state": [c.to_dict() for c in state],
"clientside_function": None,
# prevent_initial_call can be a string "initial_duplicates"
# which should not prevent the initial call.
"prevent_initial_call": prevent_initial_call is True,
"background": background
and {
"interval": background["interval"],
},
"dynamic_creator": dynamic_creator,
"no_output": no_output,
}
if running:
callback_spec["running"] = running
callback_map[callback_id] = {
"inputs": callback_spec["inputs"],
"state": callback_spec["state"],
"outputs_indices": outputs_indices,
"inputs_state_indices": inputs_state_indices,
"background": background,
"output": output,
"raw_inputs": inputs,
"manager": manager,
"allow_dynamic_callbacks": dynamic_creator,
"no_output": no_output,
}
callback_list.append(callback_spec)
return callback_id
def _set_side_update(ctx, response) -> bool:
side_update = dict(ctx.updated_props)
if len(side_update) > 0:
response["sideUpdate"] = side_update
return True
return False
def _initialize_context(args, kwargs, inputs_state_indices, has_output, insert_output):
"""Initialize context and validate output specifications."""
app = kwargs.pop("app", None)
output_spec = kwargs.pop("outputs_list")
callback_ctx = kwargs.pop("callback_context", AttributeDict({"updated_props": {}}))
context_value.set(callback_ctx)
original_packages = set(ComponentRegistry.registry)
if has_output:
_validate.validate_output_spec(insert_output, output_spec, Output)
func_args, func_kwargs = _validate.validate_and_group_input_args(
args, inputs_state_indices
)
return (
output_spec,
callback_ctx,
func_args,
func_kwargs,
app,
original_packages,
False,
)
def _get_callback_manager(
kwargs: dict, background: dict
) -> Union[BaseBackgroundCallbackManager, None]:
"""Set up the background callback and manage jobs."""
callback_manager = background.get(
"manager", kwargs.get("background_callback_manager", None)
)
if background is not None:
if not callback_manager:
raise MissingLongCallbackManagerError(
"Running `background` callbacks requires a manager to be installed.\n"
"Available managers:\n"
"- Diskcache (`pip install dash[diskcache]`) to run callbacks in a separate Process"
" and store results on the local filesystem.\n"
"- Celery (`pip install dash[celery]`) to run callbacks in a celery worker"
" and store results on redis.\n"
)
old_job = flask.request.args.getlist("oldJob")
if old_job:
for job in old_job:
callback_manager.terminate_job(job)
return callback_manager
def _setup_background_callback(
kwargs, background, background_key, func, func_args, func_kwargs, callback_ctx
):
"""Set up the background callback and manage jobs."""
callback_manager = _get_callback_manager(kwargs, background)
progress_outputs = background.get("progress")
cache_ignore_triggered = background.get("cache_ignore_triggered", True)
cache_key = callback_manager.build_cache_key(
func,
# Inputs provided as dict is kwargs.
func_args if func_args else func_kwargs,
background.get("cache_args_to_ignore", []),
None if cache_ignore_triggered else callback_ctx.get("triggered_inputs", []),
)
job_fn = callback_manager.func_registry.get(background_key)
ctx_value = AttributeDict(**context_value.get())
ctx_value.ignore_register_page = True
ctx_value.pop("background_callback_manager")
ctx_value.pop("dash_response")
job = callback_manager.call_job_fn(
cache_key,
job_fn,
func_args if func_args else func_kwargs,
ctx_value,
)
data = {
"cacheKey": cache_key,
"job": job,
}
cancel = background.get("cancel")
if cancel:
data["cancel"] = cancel
progress_default = background.get("progressDefault")
if progress_default:
data["progressDefault"] = {
str(o): x for o, x in zip(progress_outputs, progress_default)
}
return to_json(data)
def _progress_background_callback(response, callback_manager, background):
progress_outputs = background.get("progress")
cache_key = flask.request.args.get("cacheKey")
if progress_outputs:
# Get the progress before the result as it would be erased after the results.
progress = callback_manager.get_progress(cache_key)
if progress:
response["progress"] = {
str(x): progress[i] for i, x in enumerate(progress_outputs)
}
def _update_background_callback(
error_handler, callback_ctx, response, kwargs, background, multi
):
"""Set up the background callback and manage jobs."""
callback_manager = _get_callback_manager(kwargs, background)
cache_key = flask.request.args.get("cacheKey")
job_id = flask.request.args.get("job")
_progress_background_callback(response, callback_manager, background)
output_value = callback_manager.get_result(cache_key, job_id)
return _handle_rest_background_callback(
output_value, callback_manager, response, error_handler, callback_ctx, multi
)
def _handle_rest_background_callback(
output_value,
callback_manager,
response,
error_handler,
callback_ctx,
multi,
has_update=False,
):
cache_key = flask.request.args.get("cacheKey")
job_id = flask.request.args.get("job")
# Must get job_running after get_result since get_results terminates it.
job_running = callback_manager.job_running(job_id)
if not job_running and output_value is callback_manager.UNDEFINED:
# Job canceled -> no output to close the loop.
output_value = NoUpdate()
elif isinstance(output_value, dict) and "background_callback_error" in output_value:
error = output_value.get("background_callback_error", {})
exc = BackgroundCallbackError(
f"An error occurred inside a background callback: {error['msg']}\n{error['tb']}"
)
if error_handler:
output_value = error_handler(exc)
if output_value is None:
output_value = NoUpdate()
# set_props from the error handler uses the original ctx
# instead of manager.get_updated_props since it runs in the
# request process.
has_update = (
_set_side_update(callback_ctx, response) or output_value is not None
)
else:
raise exc
if job_running and output_value is not callback_manager.UNDEFINED:
# cached results.
callback_manager.terminate_job(job_id)
if multi and isinstance(output_value, (list, tuple)):
output_value = [
NoUpdate() if NoUpdate.is_no_update(r) else r for r in output_value
]
updated_props = callback_manager.get_updated_props(cache_key)
if len(updated_props) > 0:
response["sideUpdate"] = updated_props
has_update = True
if output_value is callback_manager.UNDEFINED:
return to_json(response), has_update, True
return output_value, has_update, False
# pylint: disable=too-many-branches
def _prepare_response(
output_value,
output_spec,
multi,
response,
callback_ctx,
app,
original_packages,
background,
has_update,
has_output,
output,
callback_id,
allow_dynamic_callbacks,
):
"""Prepare the response object based on the callback output."""
component_ids = collections.defaultdict(dict)
if has_output:
if not multi:
output_value, output_spec = [output_value], [output_spec]
flat_output_values = output_value
else:
if isinstance(output_value, (list, tuple)):
# For multi-output, allow top-level collection to be
# list or tuple
output_value = list(output_value)
if NoUpdate.is_no_update(output_value):
flat_output_values = [output_value]
else:
# Flatten grouping and validate grouping structure
flat_output_values = flatten_grouping(output_value, output)
if not NoUpdate.is_no_update(output_value):
_validate.validate_multi_return(
output_spec, flat_output_values, callback_id
)
for val, spec in zip(flat_output_values, output_spec):
if NoUpdate.is_no_update(val):
continue
for vali, speci in (
zip(val, spec) if isinstance(spec, list) else [[val, spec]] # type: ignore[reportArgumentType]
):
if not NoUpdate.is_no_update(vali):
has_update = True
id_str = stringify_id(speci["id"])
prop = clean_property_name(speci["property"])
component_ids[id_str][prop] = vali
else:
if output_value is not None:
raise InvalidCallbackReturnValue(
f"No-output callback received return value: {output_value}"
)
if not background:
has_update = _set_side_update(callback_ctx, response) or has_output
if not has_update:
raise PreventUpdate
if len(ComponentRegistry.registry) != len(original_packages):
diff_packages = list(
set(ComponentRegistry.registry).difference(original_packages)
)
if not allow_dynamic_callbacks:
raise ImportedInsideCallbackError(
f"Component librar{'y' if len(diff_packages) == 1 else 'ies'} was imported during callback.\n"
"You can set `_allow_dynamic_callbacks` to allow for development purpose only."
)
dist = app.get_dist(diff_packages)
response["dist"] = dist
return response.update({"response": component_ids})
# pylint: disable=too-many-branches,too-many-statements
def register_callback(
callback_list, callback_map, config_prevent_initial_callbacks, *_args, **_kwargs
):
(
output,
flat_inputs,
flat_state,
inputs_state_indices,
prevent_initial_call,
) = handle_grouped_callback_args(_args, _kwargs)
if isinstance(output, Output):
# Insert callback with scalar (non-multi) Output
insert_output = output
multi = False
has_output = True
else:
# Insert callback as multi Output
insert_output = flatten_grouping(output)
multi = True
has_output = len(output) > 0
background = _kwargs.get("background")
manager = _kwargs.get("manager")
running = _kwargs.get("running")
on_error = _kwargs.get("on_error")
if running is not None:
if not isinstance(running[0], (list, tuple)):
running = [running]
running = {
"running": {str(r[0]): r[1] for r in running},
"runningOff": {str(r[0]): r[2] for r in running},
}
allow_dynamic_callbacks = _kwargs.get("_allow_dynamic_callbacks")
output_indices = make_grouping_by_index(output, list(range(grouping_len(output))))
callback_id = insert_callback(
callback_list,
callback_map,
config_prevent_initial_callbacks,
insert_output,
output_indices,
flat_inputs,
flat_state,
inputs_state_indices,
prevent_initial_call,
background=background,
manager=manager,
dynamic_creator=allow_dynamic_callbacks,
running=running,
no_output=not has_output,
)
# pylint: disable=too-many-locals
def wrap_func(func):
if background is None:
background_key = None
else:
background_key = BaseBackgroundCallbackManager.register_func(
func,
background.get("progress") is not None,
callback_id,
)
@wraps(func)
def add_context(*args, **kwargs):
"""Handles synchronous callbacks with context management."""
error_handler = on_error or kwargs.pop("app_on_error", None)
(
output_spec,
callback_ctx,
func_args,
func_kwargs,
app,
original_packages,
has_update,
) = _initialize_context(
args, kwargs, inputs_state_indices, has_output, insert_output
)
response: dict = {"multi": True}
jsonResponse = None
try:
if background is not None:
if not flask.request.args.get("cacheKey"):
return _setup_background_callback(
kwargs,
background,
background_key,
func,
func_args,
func_kwargs,
callback_ctx,
)
output_value, has_update, skip = _update_background_callback(
error_handler, callback_ctx, response, kwargs, background, multi
)
if skip:
return output_value
else:
output_value = _invoke_callback(func, *func_args, **func_kwargs) # type: ignore[reportArgumentType]
except PreventUpdate:
raise
except Exception as err: # pylint: disable=broad-exception-caught
if error_handler:
output_value = error_handler(err)
if output_value is None and output_spec:
output_value = NoUpdate()
else:
raise err
_prepare_response(
output_value,
output_spec,
multi,
response,
callback_ctx,
app,
original_packages,
background,
has_update,
has_output,
output,
callback_id,
allow_dynamic_callbacks,
)
try:
jsonResponse = to_json(response)
except TypeError:
_validate.fail_callback_output(output_value, output)
return jsonResponse
@wraps(func)
async def async_add_context(*args, **kwargs):
"""Handles async callbacks with context management."""
error_handler = on_error or kwargs.pop("app_on_error", None)
(
output_spec,
callback_ctx,
func_args,
func_kwargs,
app,
original_packages,
has_update,
) = _initialize_context(
args, kwargs, inputs_state_indices, has_output, insert_output
)
response: dict = {"multi": True}
try:
if background is not None:
if not flask.request.args.get("cacheKey"):
return _setup_background_callback(
kwargs,
background,
background_key,
func,
func_args,
func_kwargs,
callback_ctx,
)
output_value, has_update, skip = _update_background_callback(
error_handler, callback_ctx, response, kwargs, background, multi
)
if skip:
return output_value
else:
output_value = await _async_invoke_callback(
func, *func_args, **func_kwargs
)
except PreventUpdate:
raise
except Exception as err: # pylint: disable=broad-exception-caught
if error_handler:
output_value = error_handler(err)
if output_value is None and output_spec:
output_value = NoUpdate()
else:
raise err
_prepare_response(
output_value,
output_spec,
multi,
response,
callback_ctx,
app,
original_packages,
background,
has_update,
has_output,
output,
callback_id,
allow_dynamic_callbacks,
)
try:
jsonResponse = to_json(response)
except TypeError:
_validate.fail_callback_output(output_value, output)
return jsonResponse
if asyncio.iscoroutinefunction(func):
callback_map[callback_id]["callback"] = async_add_context
else:
callback_map[callback_id]["callback"] = add_context
return func
return wrap_func
_inline_clientside_template = """
(function() {{
var clientside = window.dash_clientside = window.dash_clientside || {{}};
var ns = clientside["{namespace}"] = clientside["{namespace}"] || {{}};
ns["{function_name}"] = {clientside_function};
}})();
"""
def register_clientside_callback(
callback_list,
callback_map,
config_prevent_initial_callbacks,
inline_scripts,
clientside_function: ClientsideFuncType,
*args,
**kwargs,
):
output, inputs, state, prevent_initial_call = handle_callback_args(args, kwargs)
no_output = isinstance(output, (list,)) and len(output) == 0
insert_callback(
callback_list,
callback_map,
config_prevent_initial_callbacks,
output,
None,
inputs,
state,
None,
prevent_initial_call,
no_output=no_output,
)
# If JS source is explicitly given, create a namespace and function
# name, then inject the code.
if isinstance(clientside_function, str):
namespace = "_dashprivate_clientside_funcs"
# Create a hash from the function, it will be the same always
function_name = hashlib.sha256(clientside_function.encode("utf-8")).hexdigest()
inline_scripts.append(
_inline_clientside_template.format(
namespace=namespace,
function_name=function_name,
clientside_function=clientside_function,
)
)
# Callback is stored in an external asset.
else:
namespace = clientside_function.namespace
function_name = clientside_function.function_name
callback_list[-1]["clientside_function"] = {
"namespace": namespace,
"function_name": function_name,
}
@@ -0,0 +1,323 @@
import functools
import warnings
import json
import contextvars
import typing
import flask
from . import exceptions
from ._utils import AttributeDict, stringify_id
context_value = contextvars.ContextVar("callback_context")
context_value.set({})
def has_context(func):
@functools.wraps(func)
def assert_context(*args, **kwargs):
if not context_value.get():
raise exceptions.MissingCallbackContextException(
f"dash.callback_context.{getattr(func, '__name__')} is only available from a callback!"
)
return func(*args, **kwargs)
return assert_context
def _get_context_value():
return context_value.get()
def _get_from_context(key, default):
return getattr(_get_context_value(), key, default)
class FalsyList(list):
def __bool__(self):
# for Python 3
return False
def __nonzero__(self):
# for Python 2
return False
falsy_triggered = FalsyList([{"prop_id": ".", "value": None}])
# pylint: disable=no-init
class CallbackContext:
@property
@has_context
def inputs(self):
return getattr(_get_context_value(), "input_values", {})
@property
@has_context
def states(self):
return getattr(_get_context_value(), "state_values", {})
@property
@has_context
def triggered(self):
"""
Returns a list of all the Input props that changed and caused the callback to execute. It is empty when the
callback is called on initial load, unless an Input prop got its value from another initial callback.
Callbacks triggered by user actions typically have one item in triggered, unless the same action changes
two props at once or the callback has several Input props that are all modified by another callback based on
a single user action.
Example: To get the id of the component that triggered the callback:
`component_id = ctx.triggered[0]['prop_id'].split('.')[0]`
Example: To detect initial call, empty triggered is not really empty, it's falsy so that you can use:
`if ctx.triggered:`
"""
# For backward compatibility: previously `triggered` always had a
# value - to avoid breaking existing apps, add a dummy item but
# make the list still look falsy. So `if ctx.triggered` will make it
# look empty, but you can still do `triggered[0]["prop_id"].split(".")`
return getattr(_get_context_value(), "triggered_inputs", []) or falsy_triggered
@property
@has_context
def triggered_prop_ids(self):
"""
Returns a dictionary of all the Input props that changed and caused the callback to execute. It is empty when
the callback is called on initial load, unless an Input prop got its value from another initial callback.
Callbacks triggered by user actions typically have one item in triggered, unless the same action changes
two props at once or the callback has several Input props that are all modified by another callback based
on a single user action.
triggered_prop_ids (dict):
- keys (str) : the triggered "prop_id" composed of "component_id.component_property"
- values (str or dict): the id of the component that triggered the callback. Will be the dict id for pattern matching callbacks
Example - regular callback
{"btn-1.n_clicks": "btn-1"}
Example - pattern matching callbacks:
{'{"index":0,"type":"filter-dropdown"}.value': {"index":0,"type":"filter-dropdown"}}
Example usage:
`if "btn-1.n_clicks" in ctx.triggered_prop_ids:
do_something()`
"""
triggered = getattr(_get_context_value(), "triggered_inputs", [])
ids = AttributeDict({})
for item in triggered:
component_id, _, _ = item["prop_id"].rpartition(".")
ids[item["prop_id"]] = component_id
if component_id.startswith("{"):
ids[item["prop_id"]] = AttributeDict(json.loads(component_id))
return ids
@property
@has_context
def triggered_id(self):
"""
Returns the component id (str or dict) of the Input component that triggered the callback.
Note - use `triggered_prop_ids` if you need both the component id and the prop that triggered the callback or if
multiple Inputs triggered the callback.
Example usage:
`if "btn-1" == ctx.triggered_id:
do_something()`
"""
component_id = None
if self.triggered:
prop_id = self.triggered_prop_ids.first()
component_id = self.triggered_prop_ids[prop_id]
return component_id
@property
@has_context
def args_grouping(self):
"""
args_grouping is a dict of the inputs used with flexible callback signatures. The keys are the variable names
and the values are dictionaries containing:
- “id”: (string or dict) the component id. If its a pattern matching id, it will be a dict.
- “id_str”: (str) for pattern matching ids, its the stringified dict id with no white spaces.
- “property”: (str) The component property used in the callback.
- “value”: the value of the component property at the time the callback was fired.
- “triggered”: (bool)Whether this input triggered the callback.
Example usage:
@app.callback(
Output("container", "children"),
inputs=dict(btn1=Input("btn-1", "n_clicks"), btn2=Input("btn-2", "n_clicks")),
)
def display(btn1, btn2):
c = ctx.args_grouping
if c.btn1.triggered:
return f"Button 1 clicked {btn1} times"
elif c.btn2.triggered:
return f"Button 2 clicked {btn2} times"
else:
return "No clicks yet"
"""
return getattr(_get_context_value(), "args_grouping", [])
@property
@has_context
def outputs_grouping(self):
return getattr(_get_context_value(), "outputs_grouping", [])
@property
@has_context
def outputs_list(self):
if self.using_outputs_grouping:
warnings.warn(
"outputs_list is deprecated, use outputs_grouping instead",
DeprecationWarning,
)
return getattr(_get_context_value(), "outputs_list", [])
@property
@has_context
def inputs_list(self):
if self.using_args_grouping:
warnings.warn(
"inputs_list is deprecated, use args_grouping instead",
DeprecationWarning,
)
return getattr(_get_context_value(), "inputs_list", [])
@property
@has_context
def states_list(self):
if self.using_args_grouping:
warnings.warn(
"states_list is deprecated, use args_grouping instead",
DeprecationWarning,
)
return getattr(_get_context_value(), "states_list", [])
@property
@has_context
def response(self):
return getattr(_get_context_value(), "dash_response")
@staticmethod
@has_context
def record_timing(name, duration, description=None):
"""Records timing information for a server resource.
:param name: The name of the resource.
:type name: string
:param duration: The time in seconds to report. Internally, this
is rounded to the nearest millisecond.
:type duration: float
:param description: A description of the resource.
:type description: string or None
"""
timing_information = getattr(flask.g, "timing_information", {})
if name in timing_information:
raise KeyError(f'Duplicate resource name "{name}" found.')
timing_information[name] = {"dur": round(duration * 1000), "desc": description}
setattr(flask.g, "timing_information", timing_information)
@property
@has_context
def using_args_grouping(self):
"""
Return True if this callback is using dictionary or nested groupings for
Input/State dependencies, or if Input and State dependencies are interleaved
"""
return getattr(_get_context_value(), "using_args_grouping", [])
@property
@has_context
def using_outputs_grouping(self):
"""
Return True if this callback is using dictionary or nested groupings for
Output dependencies.
"""
return getattr(_get_context_value(), "using_outputs_grouping", [])
@property
@has_context
def timing_information(self):
return getattr(flask.g, "timing_information", {})
@has_context
def set_props(self, component_id: typing.Union[str, dict], props: dict):
ctx_value = _get_context_value()
_id = stringify_id(component_id)
existing = ctx_value.updated_props.get(_id)
if existing is not None:
ctx_value.updated_props[_id] = {**existing, **props}
else:
ctx_value.updated_props[_id] = props
@property
@has_context
def cookies(self):
"""
Get the cookies for the current callback.
Works with background callbacks.
"""
return _get_from_context("cookies", {})
@property
@has_context
def headers(self):
"""
Get the original headers for the current callback.
Works with background callbacks.
"""
return _get_from_context("headers", {})
@property
@has_context
def path(self):
"""
Path of the callback request with the query parameters.
"""
return _get_from_context("path", "")
@property
@has_context
def remote(self):
"""
Remote addr of the callback request.
"""
return _get_from_context("remote", "")
@property
@has_context
def origin(self):
"""
Origin of the callback request.
"""
return _get_from_context("origin", "")
@property
@has_context
def custom_data(self):
"""
Custom data set by hooks.custom_data.
"""
return _get_from_context("custom_data", {})
callback_context = CallbackContext()
def set_props(component_id: typing.Union[str, dict], props: dict):
"""
Set the props for a component not included in the callback outputs.
"""
callback_context.set_props(component_id, props)
@@ -0,0 +1,138 @@
import os
import flask
# noinspection PyCompatibility
from . import exceptions
from ._utils import AttributeDict
def load_dash_env_vars():
return AttributeDict(
{
var: os.getenv(var, os.getenv(var.lower()))
for var in (
"DASH_APP_NAME",
"DASH_URL_BASE_PATHNAME",
"DASH_ROUTES_PATHNAME_PREFIX",
"DASH_REQUESTS_PATHNAME_PREFIX",
"DASH_SUPPRESS_CALLBACK_EXCEPTIONS",
"DASH_ASSETS_EXTERNAL_PATH",
"DASH_INCLUDE_ASSETS_FILES",
"DASH_COMPONENTS_CACHE_MAX_AGE",
"DASH_INCLUDE_ASSETS_FILES",
"DASH_SERVE_DEV_BUNDLES",
"DASH_DEBUG",
"DASH_UI",
"DASH_PROPS_CHECK",
"DASH_HOT_RELOAD",
"DASH_HOT_RELOAD_INTERVAL",
"DASH_HOT_RELOAD_WATCH_INTERVAL",
"DASH_HOT_RELOAD_MAX_RETRY",
"DASH_SILENCE_ROUTES_LOGGING",
"DASH_DISABLE_VERSION_CHECK",
"DASH_PRUNE_ERRORS",
"DASH_COMPRESS",
"HOST",
"PORT",
)
}
)
DASH_ENV_VARS = load_dash_env_vars() # used in tests
def get_combined_config(name, val, default=None):
"""Consolidate the config with priority from high to low provided init
value > OS environ > default."""
if val is not None:
return val
env = load_dash_env_vars().get(f"DASH_{name.upper()}")
if env is None:
return default
return env.lower() == "true" if env.lower() in {"true", "false"} else env
def pathname_configs(
url_base_pathname=None, routes_pathname_prefix=None, requests_pathname_prefix=None
):
_pathname_config_error_message = """
{} This is ambiguous.
To fix this, set `routes_pathname_prefix` instead of `url_base_pathname`.
Note that `requests_pathname_prefix` is the prefix for the AJAX calls that
originate from the client (the web browser) and `routes_pathname_prefix` is
the prefix for the API routes on the backend (this flask server).
`url_base_pathname` will set `requests_pathname_prefix` and
`routes_pathname_prefix` to the same value.
If you need these to be different values then you should set
`requests_pathname_prefix` and `routes_pathname_prefix`,
not `url_base_pathname`.
"""
url_base_pathname = get_combined_config("url_base_pathname", url_base_pathname)
routes_pathname_prefix = get_combined_config(
"routes_pathname_prefix", routes_pathname_prefix
)
requests_pathname_prefix = get_combined_config(
"requests_pathname_prefix", requests_pathname_prefix
)
if url_base_pathname is not None and requests_pathname_prefix is not None:
raise exceptions.InvalidConfig(
_pathname_config_error_message.format(
"You supplied `url_base_pathname` and `requests_pathname_prefix`."
)
)
if url_base_pathname is not None and routes_pathname_prefix is not None:
raise exceptions.InvalidConfig(
_pathname_config_error_message.format(
"You supplied `url_base_pathname` and `routes_pathname_prefix`."
)
)
if url_base_pathname is not None and routes_pathname_prefix is None:
routes_pathname_prefix = url_base_pathname
elif routes_pathname_prefix is None:
routes_pathname_prefix = "/"
if not routes_pathname_prefix.startswith("/"):
raise exceptions.InvalidConfig(
"`routes_pathname_prefix` needs to start with `/`"
)
if not routes_pathname_prefix.endswith("/"):
raise exceptions.InvalidConfig("`routes_pathname_prefix` needs to end with `/`")
app_name = load_dash_env_vars().DASH_APP_NAME
if not requests_pathname_prefix and app_name:
requests_pathname_prefix = "/" + app_name + routes_pathname_prefix
elif requests_pathname_prefix is None:
requests_pathname_prefix = routes_pathname_prefix
if not requests_pathname_prefix.startswith("/"):
raise exceptions.InvalidConfig(
"`requests_pathname_prefix` needs to start with `/`"
)
return url_base_pathname, routes_pathname_prefix, requests_pathname_prefix
def pages_folder_config(name, pages_folder, use_pages):
if not pages_folder:
return None
is_custom_folder = str(pages_folder) != "pages"
pages_folder_path = os.path.join(flask.helpers.get_root_path(name), pages_folder)
if (use_pages or is_custom_folder) and not os.path.isdir(pages_folder_path):
error_msg = f"""
A folder called `{pages_folder}` does not exist. If a folder for pages is not
required in your application, set `pages_folder=""`. For example:
`app = Dash(__name__, pages_folder="")`
"""
raise exceptions.InvalidConfig(error_msg)
return pages_folder_path
@@ -0,0 +1,77 @@
import os
__version__ = "2.2.0"
_available_react_versions = {"18.3.1", "18.2.0", "16.14.0"}
_available_reactdom_versions = {"18.3.1", "18.2.0", "16.14.0"}
_js_dist_dependencies = [] # to be set by _set_react_version
def _set_react_version(v_react, v_reactdom=None):
if not v_reactdom:
v_reactdom = v_react
react_err = f"looking for one of {_available_react_versions}, found {v_react}"
reactdom_err = (
f"looking for one of {_available_reactdom_versions}, found {v_reactdom}"
)
assert v_react in _available_react_versions, react_err
assert v_reactdom in _available_reactdom_versions, reactdom_err
_js_dist_dependencies[:] = [
{
"external_url": {
"prod": [
"https://unpkg.com/@babel/polyfill@7.12.1/dist/polyfill.min.js",
f"https://unpkg.com/react@{v_react}/umd/react.production.min.js",
f"https://unpkg.com/react-dom@{v_reactdom}/umd/react-dom.production.min.js",
"https://unpkg.com/prop-types@15.8.1/prop-types.min.js",
],
"dev": [
"https://unpkg.com/@babel/polyfill@7.12.1/dist/polyfill.min.js",
f"https://unpkg.com/react@{v_react}/umd/react.development.js",
f"https://unpkg.com/react-dom@{v_reactdom}/umd/react-dom.development.js",
"https://unpkg.com/prop-types@15.8.1/prop-types.js",
],
},
"relative_package_path": {
"prod": [
"deps/polyfill@7.12.1.min.js",
f"deps/react@{v_react}.min.js",
f"deps/react-dom@{v_reactdom}.min.js",
"deps/prop-types@15.8.1.min.js",
],
"dev": [
"deps/polyfill@7.12.1.min.js",
f"deps/react@{v_react}.js",
f"deps/react-dom@{v_reactdom}.js",
"deps/prop-types@15.8.1.js",
],
},
"namespace": "dash",
}
]
_env_react_version = os.getenv("REACT_VERSION")
if _env_react_version:
_set_react_version(_env_react_version)
print(f"EXPERIMENTAL: Using react version from env: {_env_react_version}")
else:
_set_react_version("18.3.1", "18.3.1")
_js_dist = [
{
"relative_package_path": "dash-renderer/build/dash_renderer.min.js",
"dev_package_path": "dash-renderer/build/dash_renderer.dev.js",
"external_url": "https://unpkg.com/dash-renderer@2.2.0"
"/build/dash_renderer.min.js",
"namespace": "dash",
},
{
"relative_package_path": "dash-renderer/build/dash_renderer.min.js.map",
"dev_package_path": "dash-renderer/build/dash_renderer.dev.js.map",
"namespace": "dash",
"dynamic": True,
},
]
@@ -0,0 +1,20 @@
from textwrap import dedent
APP = None
def get_app():
if APP is None:
raise Exception(
dedent(
"""
App object is not yet defined. `app = dash.Dash()` needs to be run
before `dash.get_app()` is called and can only be used within apps that use
the `pages` multi-page app feature: `dash.Dash(use_pages=True)`.
`dash.get_app()` is used to get around circular import issues when Python files
within the pages/` folder need to reference the `app` object.
"""
)
)
return APP
@@ -0,0 +1,161 @@
from ._utils import AttributeDict
from . import exceptions
CONFIG = AttributeDict()
def get_asset_url(path):
"""
Return the URL for the provided `path` in the assets directory.
`dash.get_asset_url` is not compatible with Dash Snapshots.
Use `get_asset_url` on the app instance instead: `app.get_asset_url`.
See `app.get_asset_url` for more information.
"""
return app_get_asset_url(CONFIG, path)
def app_get_asset_url(config, path):
if config.assets_external_path:
prefix = config.assets_external_path
else:
prefix = config.requests_pathname_prefix
return "/".join(
[
# Only take the first part of the pathname
prefix.rstrip("/"),
config.assets_url_path.lstrip("/"),
path,
]
)
def get_relative_path(path):
"""
Return a path with `requests_pathname_prefix` prefixed before it.
Use this function when specifying local URL paths that will work
in environments regardless of what `requests_pathname_prefix` is.
In some deployment environments, like Dash Enterprise,
`requests_pathname_prefix` is set to the application name,
e.g. `my-dash-app`.
When working locally, `requests_pathname_prefix` might be unset and
so a relative URL like `/page-2` can just be `/page-2`.
However, when the app is deployed to a URL like `/my-dash-app`, then
`dash.get_relative_path('/page-2')` will return `/my-dash-app/page-2`.
This can be used as an alternative to `get_asset_url` as well with
`dash.get_relative_path('/assets/logo.png')`
Use this function with `dash.strip_relative_path` in callbacks that
deal with `dcc.Location` `pathname` routing.
That is, your usage may look like:
```
app.layout = html.Div([
dcc.Location(id='url'),
html.Div(id='content')
])
@dash.callback(Output('content', 'children'), [Input('url', 'pathname')])
def display_content(path):
page_name = dash.strip_relative_path(path)
if not page_name: # None or ''
return html.Div([
dcc.Link(href=dash.get_relative_path('/page-1')),
dcc.Link(href=dash.get_relative_path('/page-2')),
])
elif page_name == 'page-1':
return chapters.page_1
if page_name == "page-2":
return chapters.page_2
```
`dash.get_relative_path` is not compatible with Dash Snapshots. Use
`get_relative_path` on the app instance instead: `app.get_relative_path`.
"""
return app_get_relative_path(CONFIG.requests_pathname_prefix, path)
def app_get_relative_path(requests_pathname, path):
if requests_pathname == "/" and path == "":
return "/"
if requests_pathname != "/" and path == "":
return requests_pathname
if not path.startswith("/"):
raise exceptions.UnsupportedRelativePath(
f"""
Paths that aren't prefixed with a leading / are not supported.
You supplied: {path}
"""
)
return "/".join([requests_pathname.rstrip("/"), path.lstrip("/")])
def strip_relative_path(path):
"""
Return a path with `requests_pathname_prefix` and leading and trailing
slashes stripped from it. Also, if None is passed in, None is returned.
Use this function with `get_relative_path` in callbacks that deal
with `dcc.Location` `pathname` routing.
That is, your usage may look like:
```
app.layout = html.Div([
dcc.Location(id='url'),
html.Div(id='content')
])
@dash.callback(Output('content', 'children'), [Input('url', 'pathname')])
def display_content(path):
page_name = dash.strip_relative_path(path)
if not page_name: # None or ''
return html.Div([
dcc.Link(href=dash.get_relative_path('/page-1')),
dcc.Link(href=dash.get_relative_path('/page-2')),
])
elif page_name == 'page-1':
return chapters.page_1
if page_name == "page-2":
return chapters.page_2
```
Note that `chapters.page_1` will be served if the user visits `/page-1`
_or_ `/page-1/` since `strip_relative_path` removes the trailing slash.
Also note that `strip_relative_path` is compatible with
`get_relative_path` in environments where `requests_pathname_prefix` set.
In some deployment environments, like Dash Enterprise,
`requests_pathname_prefix` is set to the application name, e.g. `my-dash-app`.
When working locally, `requests_pathname_prefix` might be unset and
so a relative URL like `/page-2` can just be `/page-2`.
However, when the app is deployed to a URL like `/my-dash-app`, then
`dash.get_relative_path('/page-2')` will return `/my-dash-app/page-2`
The `pathname` property of `dcc.Location` will return '`/my-dash-app/page-2`'
to the callback.
In this case, `dash.strip_relative_path('/my-dash-app/page-2')`
will return `'page-2'`
For nested URLs, slashes are still included:
`dash.strip_relative_path('/page-1/sub-page-1/')` will return
`page-1/sub-page-1`
```
"""
return app_strip_relative_path(CONFIG.requests_pathname_prefix, path)
def app_strip_relative_path(requests_pathname, path):
if path is None:
return None
if (
requests_pathname != "/" and not path.startswith(requests_pathname.rstrip("/"))
) or (requests_pathname == "/" and not path.startswith("/")):
raise exceptions.UnsupportedRelativePath(
f"""
Paths that aren't prefixed with requests_pathname_prefix are not supported.
You supplied: {path} and requests_pathname_prefix was {requests_pathname}
"""
)
if requests_pathname != "/" and path.startswith(requests_pathname.rstrip("/")):
path = path.replace(
# handle the case where the path might be `/my-dash-app`
# but the requests_pathname_prefix is `/my-dash-app/`
requests_pathname.rstrip("/"),
"",
1,
)
return path.strip("/")
@@ -0,0 +1,250 @@
"""
This module contains a collection of utility function for dealing with property
groupings.
Terminology:
For the purpose of grouping and ungrouping, tuples/lists and dictionaries are considered
"composite values" and all other values are considered "scalar values".
A "grouping value" is either composite or scalar.
A "schema" is a grouping value that can be used to encode an expected grouping
structure
"""
from .exceptions import InvalidCallbackReturnValue
from ._utils import AttributeDict, stringify_id
def flatten_grouping(grouping, schema=None):
"""
Convert a grouping value to a list of scalar values
:param grouping: grouping value to flatten
:param schema: If provided, a grouping value representing the expected structure of
the input grouping value. If not provided, the grouping value is its own schema.
A schema is required in order to be able treat tuples and dicts in the input
grouping as scalar values.
:return: list of the scalar values in the input grouping
"""
stack = []
result = []
# Avoid repeated recursive Python calls by using an explicit stack
push = stack.append
pop = stack.pop
# Only validate once at the top if schema is provided
if schema is None:
schema = grouping
else:
validate_grouping(grouping, schema)
push((grouping, schema))
while stack:
group, sch = pop()
# Inline isinstance checks for perf
typ = type(sch)
if typ is tuple or typ is list:
# Avoid double recursion / excessive list construction
for ge, se in zip(group, sch):
push((ge, se))
elif typ is dict:
for k in sch:
push((group[k], sch[k]))
else:
result.append(group)
result.reverse() # Since we LIFO, leaf values are in reverse order
return result
def grouping_len(grouping):
"""
Get the length of a grouping. The length equal to the number of scalar values
contained in the grouping, which is equivalent to the length of the list that would
result from calling flatten_grouping on the grouping value.
:param grouping: The grouping value to calculate the length of
:return: non-negative integer
"""
if isinstance(grouping, (tuple, list)):
return sum([grouping_len(group_el) for group_el in grouping])
if isinstance(grouping, dict):
return sum([grouping_len(group_el) for group_el in grouping.values()])
return 1
def make_grouping_by_index(schema, flat_values):
"""
Make a grouping like the provided grouping schema, with scalar values drawn from a
flat list by index.
Note: Scalar values in schema are not used
:param schema: Grouping value encoding the structure of the grouping to return
:param flat_values: List of values with length matching the grouping_len of schema.
Elements of flat_values will become the scalar values in the resulting grouping
"""
def _perform_make_grouping_like(value, next_values):
if isinstance(value, (tuple, list)):
return list(
_perform_make_grouping_like(el, next_values)
for i, el in enumerate(value)
)
if isinstance(value, dict):
return {
k: _perform_make_grouping_like(v, next_values)
for i, (k, v) in enumerate(value.items())
}
return next_values.pop(0)
if not isinstance(flat_values, list):
raise ValueError(
"The flat_values argument must be a list. "
f"Received value of type {type(flat_values)}"
)
expected_length = len(flatten_grouping(schema))
if len(flat_values) != expected_length:
raise ValueError(
f"The specified grouping pattern requires {expected_length} "
f"elements but received {len(flat_values)}\n"
f" Grouping pattern: {repr(schema)}\n"
f" Values: {flat_values}"
)
return _perform_make_grouping_like(schema, list(flat_values))
def map_grouping(fn, grouping):
"""
Map a function over all of the scalar values of a grouping, maintaining the
grouping structure
:param fn: Single-argument function that accepts and returns scalar grouping values
:param grouping: The grouping to map the function over
:return: A new grouping with the same structure as input grouping with scalar
values updated by the input function.
"""
if isinstance(grouping, (tuple, list)):
return [map_grouping(fn, g) for g in grouping]
if isinstance(grouping, dict):
return AttributeDict({k: map_grouping(fn, g) for k, g in grouping.items()})
return fn(grouping)
def make_grouping_by_key(schema, source, default=None):
"""
Create a grouping from a schema by using the schema's scalar values to look up
items in the provided source object.
:param schema: A grouping of potential keys in source
:param source: Dict-like object to use to look up scalar grouping value using
scalar grouping values as keys
:param default: Default scalar value to use if grouping scalar key is not present
in source
:return: grouping
"""
return map_grouping(lambda s: source.get(s, default), schema)
class SchemaTypeValidationError(InvalidCallbackReturnValue):
def __init__(self, value, full_schema, path, expected_type):
super().__init__(
msg=f"""
Schema: {full_schema}
Path: {repr(path)}
Expected type: {expected_type}
Received value of type {type(value)}:
{repr(value)}
"""
)
@classmethod
def check(cls, value, full_schema, path, expected_type):
if not isinstance(value, expected_type):
raise SchemaTypeValidationError(value, full_schema, path, expected_type)
class SchemaLengthValidationError(InvalidCallbackReturnValue):
def __init__(self, value, full_schema, path, expected_len):
super().__init__(
msg=f"""
Schema: {full_schema}
Path: {repr(path)}
Expected length: {expected_len}
Received value of length {len(value)}:
{repr(value)}
"""
)
@classmethod
def check(cls, value, full_schema, path, expected_len):
if len(value) != expected_len:
raise SchemaLengthValidationError(value, full_schema, path, expected_len)
class SchemaKeysValidationError(InvalidCallbackReturnValue):
def __init__(self, value, full_schema, path, expected_keys):
super().__init__(
msg=f"""
Schema: {full_schema}
Path: {repr(path)}
Expected keys: {expected_keys}
Received value with keys {set(value.keys())}:
{repr(value)}
"""
)
@classmethod
def check(cls, value, full_schema, path, expected_keys):
if set(value.keys()) != set(expected_keys):
raise SchemaKeysValidationError(value, full_schema, path, expected_keys)
def validate_grouping(grouping, schema, full_schema=None, path=()):
"""
Validate that the provided grouping conforms to the provided schema.
If not, raise a SchemaValidationError
"""
if full_schema is None:
full_schema = schema
if isinstance(schema, (tuple, list)):
SchemaTypeValidationError.check(grouping, full_schema, path, (tuple, list))
SchemaLengthValidationError.check(grouping, full_schema, path, len(schema))
for i, (g, s) in enumerate(zip(grouping, schema)):
validate_grouping(g, s, full_schema=full_schema, path=path + (i,))
elif isinstance(schema, dict):
SchemaTypeValidationError.check(grouping, full_schema, path, dict)
SchemaKeysValidationError.check(grouping, full_schema, path, set(schema))
for k in schema:
validate_grouping(
grouping[k], schema[k], full_schema=full_schema, path=path + (k,)
)
else:
pass
def update_args_group(g, triggered):
if isinstance(g, dict):
str_id = stringify_id(g["id"])
prop_id = f"{str_id}.{g['property']}"
new_values = {
"value": g.get("value"),
"str_id": str_id,
"triggered": prop_id in triggered,
"id": AttributeDict(g["id"]) if isinstance(g["id"], dict) else g["id"],
}
g.update(new_values)
+276
View File
@@ -0,0 +1,276 @@
import typing as _t
from importlib import metadata as _importlib_metadata
import typing_extensions as _tx
import flask as _f
from .exceptions import HookError
from .resources import ResourceType
from ._callback import ClientsideFuncType
if _t.TYPE_CHECKING:
from .dash import Dash
from .development.base_component import Component
ComponentType = _t.TypeVar("ComponentType", bound=Component)
LayoutType = _t.Union[ComponentType, _t.List[ComponentType]]
else:
LayoutType = None
ComponentType = None
Dash = None
HookDataType = _tx.TypeVar("HookDataType")
# pylint: disable=too-few-public-methods
class _Hook(_tx.Generic[HookDataType]):
def __init__(self, func, priority=0, final=False, data: HookDataType = None):
self.func = func
self.final = final
self.data = data
self.priority = priority
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
class _Hooks:
def __init__(self) -> None:
self._ns = {
"setup": [],
"layout": [],
"routes": [],
"error": [],
"callback": [],
"index": [],
"custom_data": [],
"dev_tools": [],
}
self._js_dist = []
self._css_dist = []
self._clientside_callbacks: _t.List[
_t.Tuple[ClientsideFuncType, _t.Any, _t.Any]
] = []
# final hooks are a single hook added to the end of regular hooks.
self._finals = {}
def add_hook(
self,
hook: str,
func: _t.Callable,
priority: _t.Optional[int] = None,
final: bool = False,
data: _t.Optional[HookDataType] = None,
):
if final:
existing = self._finals.get(hook)
if existing:
raise HookError("Final hook already present")
self._finals[hook] = _Hook(func, final, data=data)
return
hks = self._ns.get(hook, [])
p = priority or 0
if not priority and len(hks):
# Take the minimum value and remove 1 to keep the order.
priority_min = min(h.priority for h in hks)
p = priority_min - 1
hks.append(_Hook(func, priority=p, data=data))
self._ns[hook] = sorted(hks, reverse=True, key=lambda h: h.priority)
def get_hooks(self, hook: str) -> _t.List[_Hook]:
final = self._finals.get(hook, None)
if final:
final = [final]
else:
final = []
return self._ns.get(hook, []) + final
def layout(self, priority: _t.Optional[int] = None, final: bool = False):
"""
Run a function when serving the layout, the return value
will be used as the layout.
"""
def _wrap(func: _t.Callable[[LayoutType], LayoutType]):
self.add_hook("layout", func, priority=priority, final=final)
return func
return _wrap
def setup(self, priority: _t.Optional[int] = None, final: bool = False):
"""
Can be used to get a reference to the app after it is instantiated.
"""
def _setup(func: _t.Callable[[Dash], None]):
self.add_hook("setup", func, priority=priority, final=final)
return func
return _setup
def route(
self,
name: _t.Optional[str] = None,
methods: _t.Sequence[str] = ("GET",),
priority: _t.Optional[int] = None,
final: bool = False,
):
"""
Add a route to the Dash server.
"""
def wrap(func: _t.Callable[[], _f.Response]):
_name = name or func.__name__
self.add_hook(
"routes",
func,
priority=priority,
final=final,
data=dict(name=_name, methods=methods),
)
return func
return wrap
def error(self, priority: _t.Optional[int] = None, final: bool = False):
"""Automatically add an error handler to the dash app."""
def _error(func: _t.Callable[[Exception], _t.Any]):
self.add_hook("error", func, priority=priority, final=final)
return func
return _error
def callback(
self, *args, priority: _t.Optional[int] = None, final: bool = False, **kwargs
):
"""
Add a callback to all the apps with the hook installed.
"""
def wrap(func):
self.add_hook(
"callback",
func,
priority=priority,
final=final,
data=(list(args), dict(kwargs)),
)
return func
return wrap
def clientside_callback(
self, clientside_function: ClientsideFuncType, *args, **kwargs
):
"""
Add a callback to all the apps with the hook installed.
"""
self._clientside_callbacks.append((clientside_function, args, kwargs))
def script(self, distribution: _t.List[ResourceType]):
"""Add js scripts to the page."""
self._js_dist.extend(distribution)
def stylesheet(self, distribution: _t.List[ResourceType]):
"""Add stylesheets to the page."""
self._css_dist.extend(distribution)
def index(self, priority: _t.Optional[int] = None, final=False):
"""Modify the index of the apps."""
def wrap(func):
self.add_hook(
"index",
func,
priority=priority,
final=final,
)
return func
return wrap
def custom_data(
self, namespace: str, priority: _t.Optional[int] = None, final=False
):
"""
Add data to the callback_context.custom_data property under the namespace.
The hook function takes the current context_value and before the ctx is set
and has access to the flask request context.
"""
def wrap(func: _t.Callable[[_t.Dict], _t.Any]):
self.add_hook(
"custom_data",
func,
priority=priority,
final=final,
data={"namespace": namespace},
)
return func
return wrap
def devtool(self, namespace: str, component_type: str, props=None):
"""
Add a component to be rendered inside the dev tools.
If it's a dash component, it can be used in callbacks provided
that it has an id and the dependency is set with allow_optional=True.
`props` can be a function, in which case it will be called before
sending the component to the frontend.
"""
self._ns["dev_tools"].append(
{
"namespace": namespace,
"type": component_type,
"props": props or {},
}
)
hooks = _Hooks()
class HooksManager:
# Flag to only run `register_setuptools` once
_registered = False
hooks = hooks
# pylint: disable=too-few-public-methods
class HookErrorHandler:
def __init__(self, original):
self.original = original
def __call__(self, err: Exception):
result = None
if self.original:
result = self.original(err)
hook_result = None
for hook in HooksManager.get_hooks("error"):
hook_result = hook(err)
return result or hook_result
@classmethod
def get_hooks(cls, hook: str):
return cls.hooks.get_hooks(hook)
@classmethod
def register_setuptools(cls):
if cls._registered:
# Only have to register once.
return
for dist in _importlib_metadata.distributions():
for entry in dist.entry_points:
# Look for setup.py entry points named `dash_hooks`
if entry.group != "dash_hooks":
continue
entry.load()
@@ -0,0 +1,487 @@
# type: ignore
import asyncio
import io
import inspect
import logging
import os
import queue
import uuid
import sys
import threading
import time
from typing import Optional
from typing_extensions import Literal
from werkzeug.serving import make_server
try:
from IPython import get_ipython
from IPython.display import IFrame, display, Javascript
from IPython.core.display import HTML
from IPython.core.ultratb import FormattedTB
from retrying import retry
from ipykernel.comm import Comm
import nest_asyncio
import requests
_dash_comm = Comm(target_name="dash")
_dep_installed = True
except ImportError:
_dep_installed = False
_dash_comm = None
get_ipython = lambda: None
JupyterDisplayMode = Literal["inline", "external", "jupyterlab", "tab", "_none"]
def _get_skip(error: Exception):
from dash._callback import ( # pylint: disable=import-outside-toplevel
_invoke_callback,
)
tb = error.__traceback__
skip = 1
while tb.tb_next is not None:
skip += 1
tb = tb.tb_next
if tb.tb_frame.f_code is _invoke_callback.__code__:
return skip
return skip
def _custom_formatargvalues(
args,
varargs,
varkw,
locals, # pylint: disable=W0622
formatarg=str,
formatvarargs=lambda name: "*" + name,
formatvarkw=lambda name: "**" + name,
formatvalue=lambda value: "=" + repr(value),
):
"""Copied from inspect.formatargvalues, modified to place function
arguments on separate lines"""
# pylint: disable=W0622
def convert(name, locals=locals, formatarg=formatarg, formatvalue=formatvalue):
return formatarg(name) + formatvalue(locals[name])
specs = []
# pylint: disable=C0200
for i in range(len(args)):
specs.append(convert(args[i]))
if varargs:
specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
if varkw:
specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
result = "(" + ", ".join(specs) + ")"
if len(result) < 40:
return result
# Put each arg on a separate line
return "(\n " + ",\n ".join(specs) + "\n)"
_jupyter_config = {}
_caller = {}
def _send_jupyter_config_comm_request():
# If running in an ipython kernel,
# request that the front end extension send us the notebook server base URL
if get_ipython() is not None:
if _dash_comm.kernel is not None:
_caller["parent"] = _dash_comm.kernel.get_parent()
_dash_comm.send({"type": "base_url_request"})
def _jupyter_comm_response_received():
return bool(_jupyter_config)
def _request_jupyter_config(timeout=2):
# Heavily inspired by implementation of CaptureExecution in the
if _dash_comm.kernel is None:
# Not in jupyter setting
return
_send_jupyter_config_comm_request()
# Get shell and kernel
shell = get_ipython()
kernel = shell.kernel
# Start capturing shell events to replay later
captured_events = []
def capture_event(stream, ident, parent):
captured_events.append((stream, ident, parent))
kernel.shell_handlers["execute_request"] = capture_event
# increment execution count to avoid collision error
shell.execution_count += 1
# Allow kernel to execute comms until we receive the jupyter configuration comm
# response
t0 = time.time()
while True:
if (time.time() - t0) > timeout:
# give up
raise EnvironmentError(
"Unable to communicate with the jupyter_dash notebook or JupyterLab \n"
"extension required to infer Jupyter configuration."
)
if _jupyter_comm_response_received():
break
if asyncio.iscoroutinefunction(kernel.do_one_iteration):
loop = asyncio.get_event_loop()
nest_asyncio.apply(loop)
loop.run_until_complete(kernel.do_one_iteration())
else:
kernel.do_one_iteration()
# Stop capturing events, revert the kernel shell handler to the default
# execute_request behavior
kernel.shell_handlers["execute_request"] = kernel.execute_request
# Replay captured events
# need to flush before replaying so messages show up in current cell not
# replay cells
sys.stdout.flush()
sys.stderr.flush()
for stream, ident, parent in captured_events:
# Using kernel.set_parent is the key to getting the output of the replayed
# events to show up in the cells that were captured instead of the current cell
kernel.set_parent(ident, parent)
kernel.execute_request(stream, ident, parent)
class JupyterDash:
"""
Interact with dash apps inside jupyter notebooks.
"""
default_mode: JupyterDisplayMode = "inline"
alive_token = str(uuid.uuid4())
inline_exceptions: bool = True
_servers = {}
def infer_jupyter_proxy_config(self):
"""
Infer the current Jupyter server configuration. This will detect
the proper request_pathname_prefix and server_url values to use when
displaying Dash apps.Dash requests will be routed through the proxy.
Requirements:
In the classic notebook, this method requires the `dash` nbextension
which should be installed automatically with the installation of the
jupyter-dash Python package. You can see what notebook extensions are installed
by running the following command:
$ jupyter nbextension list
In JupyterLab, this method requires the `@plotly/dash-jupyterlab` labextension. This
extension should be installed automatically with the installation of the
jupyter-dash Python package, but JupyterLab must be allowed to rebuild before
the extension is activated (JupyterLab should automatically detect the
extension and produce a popup dialog asking for permission to rebuild). You can
see what JupyterLab extensions are installed by running the following command:
$ jupyter labextension list
"""
if not self.in_ipython or self.in_colab:
# No op when not running in a Jupyter context or when in Colab
return
# Assume classic notebook or JupyterLab
_request_jupyter_config()
def __init__(self):
self.in_ipython = get_ipython() is not None
self.in_colab = "google.colab" in sys.modules
if _dep_installed and self.in_ipython and _dash_comm:
@_dash_comm.on_msg
def _receive_message(msg):
prev_parent = _caller.get("parent")
if prev_parent and prev_parent != _dash_comm.kernel.get_parent():
_dash_comm.kernel.set_parent(
[prev_parent["header"]["session"]], prev_parent
)
del _caller["parent"]
msg_data = msg.get("content").get("data")
msg_type = msg_data.get("type", None)
if msg_type == "base_url_response":
_jupyter_config.update(msg_data)
# pylint: disable=too-many-locals, too-many-branches, too-many-statements
def run_app(
self,
app,
mode: Optional[JupyterDisplayMode] = None,
width="100%",
height=650,
host="127.0.0.1",
port=8050,
server_url=None,
):
"""
:type app: dash.Dash
:param mode: How to display the app on the notebook. One Of:
``"external"``: The URL of the app will be displayed in the notebook
output cell. Clicking this URL will open the app in the default
web browser.
``"inline"``: The app will be displayed inline in the notebook output cell
in an iframe.
``"jupyterlab"``: The app will be displayed in a dedicate tab in the
JupyterLab interface. Requires JupyterLab and the `jupyterlab-dash`
extension.
:param width: Width of app when displayed using mode="inline"
:param height: Height of app when displayed using mode="inline"
:param host: Host of the server
:param port: Port used by the server
:param server_url: Use if a custom url is required to display the app.
"""
# Validate / infer display mode
if self.in_colab:
valid_display_values = ["inline", "external"]
else:
valid_display_values = ["jupyterlab", "inline", "external", "tab", "_none"]
if mode is None:
mode = self.default_mode
elif not isinstance(mode, str):
raise ValueError(
f"The mode argument must be a string\n"
f" Received value of type {type(mode)}: {repr(mode)}"
)
else:
mode = mode.lower() # type: ignore
if mode not in valid_display_values:
raise ValueError(
f"Invalid display argument {mode}\n"
f" Valid arguments: {valid_display_values}"
)
# Terminate any existing server using this port
old_server = self._servers.get((host, port))
if old_server:
old_server.shutdown()
del self._servers[(host, port)]
# Configure pathname prefix
if "base_subpath" in _jupyter_config:
requests_pathname_prefix = (
_jupyter_config["base_subpath"].rstrip("/") + "/proxy/{port}/"
)
else:
requests_pathname_prefix = app.config.get("requests_pathname_prefix", None)
if requests_pathname_prefix is not None:
requests_pathname_prefix = requests_pathname_prefix.format(port=port)
else:
requests_pathname_prefix = "/"
routes_pathname_prefix = app.config.get("routes_pathname_prefix", "/")
# FIXME Move config initialization to main dash __init__
# low-level setter to circumvent Dash's config locking
# normally it's unsafe to alter requests_pathname_prefix this late, but
# Jupyter needs some unusual behavior.
dict.__setitem__(
app.config, "requests_pathname_prefix", requests_pathname_prefix
)
# # Compute server_url url
if server_url is None:
if "server_url" in _jupyter_config:
server_url = _jupyter_config["server_url"].rstrip("/")
else:
domain_base = os.environ.get("DASH_DOMAIN_BASE", None)
if domain_base:
# Dash Enterprise sets DASH_DOMAIN_BASE environment variable
server_url = "https://" + domain_base
else:
server_url = f"http://{host}:{port}"
else:
server_url = server_url.rstrip("/")
# server_url = "http://{host}:{port}".format(host=host, port=port)
dashboard_url = f"{server_url}{requests_pathname_prefix}"
# prevent partial import of orjson when it's installed and mode=jupyterlab
# TODO: why do we need this? Why only in this mode? Importing here in
# all modes anyway, in case there's a way it can pop up in another mode
try:
# pylint: disable=C0415,W0611
import orjson # noqa: F401
except ImportError:
pass
err_q = queue.Queue()
server = make_server(host, port, app.server, threaded=True, processes=0)
logging.getLogger("werkzeug").setLevel(logging.ERROR)
@retry(
stop_max_attempt_number=15,
wait_exponential_multiplier=100,
wait_exponential_max=1000,
)
def run():
try:
server.serve_forever()
except SystemExit:
pass
except Exception as error:
err_q.put(error)
raise error
thread = threading.Thread(target=run)
thread.daemon = True
thread.start()
self._servers[(host, port)] = server
# Wait for server to start up
alive_url = f"http://{host}:{port}{routes_pathname_prefix}_alive_{JupyterDash.alive_token}"
def _get_error():
try:
err = err_q.get_nowait()
if err:
raise err
except queue.Empty:
pass
# Wait for app to respond to _alive endpoint
@retry(
stop_max_attempt_number=15,
wait_exponential_multiplier=10,
wait_exponential_max=1000,
)
def wait_for_app():
_get_error()
try:
req = requests.get(alive_url)
res = req.content.decode()
if req.status_code != 200:
raise Exception(res)
if res != "Alive":
url = f"http://{host}:{port}"
raise OSError(
f"Address '{url}' already in use.\n"
" Try passing a different port to run."
)
except requests.ConnectionError as err:
_get_error()
raise err
try:
wait_for_app()
if self.in_colab:
JupyterDash._display_in_colab(dashboard_url, port, mode, width, height)
else:
JupyterDash._display_in_jupyter(
dashboard_url, port, mode, width, height
)
except Exception as final_error: # pylint: disable=broad-except
msg = str(final_error)
if msg.startswith("<!"):
display(HTML(msg))
else:
raise final_error
@staticmethod
def _display_in_colab(dashboard_url, port, mode, width, height):
# noinspection PyUnresolvedReferences
from google.colab import output # pylint: disable=E0401,E0611,C0415
if mode == "inline":
output.serve_kernel_port_as_iframe(port, width=width, height=height)
elif mode == "external":
# FIXME there is a 403 on this, maybe it's updated?
# Display a hyperlink that can be clicked to open Dashboard
print("Dash app running on:")
output.serve_kernel_port_as_window(port, anchor_text=dashboard_url)
@staticmethod
def _display_in_jupyter(dashboard_url, port, mode, width, height):
if mode == "inline":
display(IFrame(dashboard_url, width, height))
elif mode in ("external", "tab"):
# Display a hyperlink that can be clicked to open Dashboard
print(f"Dash app running on {dashboard_url}")
if mode == "tab":
display(Javascript(f"window.open('{dashboard_url}')"))
elif mode == "jupyterlab":
# Update front-end extension
# FIXME valid only in jupyterlab but accepted in regular notebooks show nothing.
_dash_comm.send(
{
"type": "show",
"port": port,
"url": dashboard_url,
}
)
@staticmethod
def serve_alive():
return "Alive"
def configure_callback_exception_handling(self, app, dev_tools_prune_errors):
"""Install traceback handling for callbacks"""
@app.server.errorhandler(Exception)
def _wrap_errors(error):
# Compute number of stack frames to skip to get down to callback
skip = _get_skip(error) if dev_tools_prune_errors else 0
# Customized formatargvalues function we can place function parameters
# on separate lines
original_formatargvalues = inspect.formatargvalues
inspect.formatargvalues = _custom_formatargvalues
try:
# Use IPython traceback formatting to build the traceback string.
ostream = io.StringIO()
ipytb = FormattedTB(
tb_offset=skip,
mode="Verbose",
color_scheme="NoColor",
include_vars=True,
ostream=ostream,
)
ipytb()
finally:
# Restore formatargvalues
inspect.formatargvalues = original_formatargvalues
stacktrace = ostream.getvalue()
if self.inline_exceptions:
print(stacktrace)
return stacktrace, 500
@property
def active(self):
_inside_dbx = "DATABRICKS_RUNTIME_VERSION" in os.environ
return _dep_installed and not _inside_dbx and (self.in_ipython or self.in_colab)
jupyter_dash = JupyterDash()
@@ -0,0 +1,11 @@
class NoUpdate:
def to_plotly_json(self): # pylint: disable=no-self-use
return {"_dash_no_update": "_dash_no_update"}
@staticmethod
def is_no_update(obj):
return (
obj is NoUpdate
or isinstance(obj, NoUpdate)
or (isinstance(obj, dict) and obj == {"_dash_no_update": "_dash_no_update"})
)
@@ -0,0 +1,23 @@
# pylint: disable=too-few-public-methods
from .exceptions import ObsoleteAttributeException
class ObsoleteAttribute:
def __init__(self, message: str, exc=ObsoleteAttributeException):
self.message = message
self.exc = exc
class ObsoleteChecker:
_obsolete_attributes = {
"run_server": ObsoleteAttribute("app.run_server has been replaced by app.run"),
"long_callback": ObsoleteAttribute(
"app.long_callback has been removed, use app.callback(..., background=True) instead"
),
}
def __getattr__(self, name: str):
if name in self._obsolete_attributes:
err = self._obsolete_attributes[name]
raise err.exc(err.message)
return getattr(self.__dict__, name)
+450
View File
@@ -0,0 +1,450 @@
import collections
import importlib
import importlib.util # to make the type checker happy
import os
import re
import sys
from fnmatch import fnmatch
from os.path import isfile, join
from pathlib import Path
from urllib.parse import parse_qs
import flask
from . import _validate
from ._callback_context import context_value
from ._get_app import get_app
from ._get_paths import get_relative_path
from ._utils import AttributeDict
CONFIG = AttributeDict()
PAGE_REGISTRY = collections.OrderedDict()
def _infer_image(module):
"""
Return:
- A page specific image: `assets/<module>.<extension>` is used, e.g. `assets/weekly_analytics.png`
- A generic app image at `assets/app.<extension>`
- A logo at `assets/logo.<extension>`
"""
assets_folder = CONFIG.assets_folder
valid_extensions = ["apng", "avif", "gif", "jpeg", "jpg", "png", "svg", "webp"]
page_id = module.split(".")[-1]
files_in_assets = []
if os.path.exists(assets_folder):
files_in_assets = [
f for f in os.listdir(assets_folder) if isfile(join(assets_folder, f))
]
app_file = None
logo_file = None
for fn in files_in_assets:
fn_without_extension, _, extension = fn.partition(".")
if extension.lower() in valid_extensions:
if (
fn_without_extension == page_id
or fn_without_extension == page_id.replace("_", "-")
):
return fn
if fn_without_extension == "app":
app_file = fn
if fn_without_extension == "logo":
logo_file = fn
if app_file:
return app_file
return logo_file
def _module_name_to_page_name(module_name):
return module_name.split(".")[-1].replace("_", " ").capitalize()
def _infer_path(module_name, template):
if template is None:
if CONFIG.pages_folder:
pages_module = str(Path(CONFIG.pages_folder).name)
path = (
module_name.split(pages_module)[-1]
.replace("_", "-")
.replace(".", "/")
.lower()
)
else:
path = module_name.replace("_", "-").replace(".", "/").lower()
else:
# replace the variables in the template with "none" to create a default path if
# no path is supplied
path = re.sub("<.*?>", "none", template)
path = "/" + path if not path.startswith("/") else path
return path
def _module_name_is_package(module_name):
if module_name not in sys.modules:
return False
file = sys.modules[module_name].__file__
return file and file.endswith("__init__.py")
def _path_to_module_name(path):
return str(path).replace(".py", "").strip(os.sep).replace(os.sep, ".")
def _infer_module_name(page_path):
relative_path = page_path.split(CONFIG.pages_folder)[-1]
module = _path_to_module_name(relative_path)
proj_root = flask.helpers.get_root_path(CONFIG.name)
if CONFIG.pages_folder.startswith(proj_root):
parent_path = CONFIG.pages_folder[len(proj_root) :]
else:
parent_path = CONFIG.pages_folder
parent_module = _path_to_module_name(parent_path)
module_name = f"{parent_module}.{module}"
if _module_name_is_package(CONFIG.name):
# Only prefix with CONFIG.name when it's an imported package name
module_name = f"{CONFIG.name}.{module_name}"
return module_name
def _parse_query_string(search):
if not search or not search.startswith("?"):
return {}
query_string = search[1:]
parsed_qs = parse_qs(query_string, keep_blank_values=True)
return {k: v[0] if len(v) == 1 else v for k, v in parsed_qs.items()}
def _parse_path_variables(pathname, path_template):
"""
creates the dict of path variables passed to the layout
e.g. path_template= "/asset/<asset_id>"
if pathname provided by the browser is "/assets/a100"
returns **{"asset_id": "a100"}
"""
# parse variable definitions e.g. <var_name> from template
# and create pattern to match
wildcard_pattern = re.sub("<.*?>", "*", path_template)
var_pattern = re.sub("<.*?>", "(.*)", path_template)
# check that static sections of the pathname match the template
if not fnmatch(pathname, wildcard_pattern):
return None
# parse variable names e.g. var_name from template
var_names = re.findall("<(.*?)>", path_template)
# parse variables from path
variables = re.findall(var_pattern, pathname)
variables = variables[0] if isinstance(variables[0], tuple) else variables
return dict(zip(var_names, variables))
def _create_redirect_function(redirect_to):
def redirect():
return flask.redirect(redirect_to, code=301)
return redirect
def _set_redirect(redirect_from, path):
app = get_app()
if redirect_from and len(redirect_from):
for redirect in redirect_from:
fullname = app.get_relative_path(redirect)
app.server.add_url_rule(
fullname,
fullname,
_create_redirect_function(app.get_relative_path(path)),
)
def register_page(
module,
path=None,
path_template=None,
name=None,
order=None,
title=None,
description=None,
image=None,
image_url=None,
redirect_from=None,
layout=None,
**kwargs,
):
"""
Assigns the variables to `dash.page_registry` as an `OrderedDict`
(ordered by `order`).
`dash.page_registry` is used by `pages_plugin` to set up the layouts as
a multi-page Dash app. This includes the URL routing callbacks
(using `dcc.Location`) and the HTML templates to include title,
meta description, and the meta description image.
`dash.page_registry` can also be used by Dash developers to create the
page navigation links or by template authors.
- `module`:
The module path where this page's `layout` is defined. Often `__name__`.
- `path`:
URL Path, e.g. `/` or `/home-page`.
If not supplied, will be inferred from the `path_template` or `module`,
e.g. based on path_template: `/asset/<asset_id` to `/asset/none`
e.g. based on module: `pages.weekly_analytics` to `/weekly-analytics`
- `relative_path`:
The path with `requests_pathname_prefix` prefixed before it.
Use this path when specifying local URL paths that will work
in environments regardless of what `requests_pathname_prefix` is.
In some deployment environments, like Dash Enterprise,
`requests_pathname_prefix` is set to the application name,
e.g. `my-dash-app`.
When working locally, `requests_pathname_prefix` might be unset and
so a relative URL like `/page-2` can just be `/page-2`.
However, when the app is deployed to a URL like `/my-dash-app`, then
`relative_path` will be `/my-dash-app/page-2`.
- `path_template`:
Add variables to a URL by marking sections with <variable_name>. The layout function
then receives the <variable_name> as a keyword argument.
e.g. path_template= "/asset/<asset_id>"
then if pathname in browser is "/assets/a100" then layout will receive **{"asset_id":"a100"}
- `name`:
The name of the link.
If not supplied, will be inferred from `module`,
e.g. `pages.weekly_analytics` to `Weekly analytics`
- `order`:
The order of the pages in `page_registry`.
If not supplied, then the filename is used and the page with path `/` has
order `0`
- `title`:
(string or function) Specifies the page title displayed in the browser tab.
If not supplied, the app's title is used if different from the default "Dash".
Otherwise, the title is the given `name` or inferred from the module name.
For example, `pages.weekly_analytics` is inferred as "Weekly Analytics".
- `description`:
(string or function) The <meta type="description"></meta>.
If not defined, the application description will be used if available.
- `image`:
The meta description image used by social media platforms.
If not supplied, then it looks for the following images in `assets/`:
- A page specific image: `assets/<module>.<extension>` is used, e.g. `assets/weekly_analytics.png`
- A generic app image at `assets/app.<extension>`
- A logo at `assets/logo.<extension>`
When inferring the image file, it will look for the following extensions:
APNG, AVIF, GIF, JPEG, JPG, PNG, SVG, WebP.
- `image_url`:
Overrides the image property and sets the `<image>` meta tag to the provided image URL.
- `redirect_from`:
A list of paths that should redirect to this page.
For example: `redirect_from=['/v2', '/v3']`
- `layout`:
The layout function or component for this page.
If not supplied, then looks for `layout` from within the supplied `module`.
- `**kwargs`:
Arbitrary keyword arguments that can be stored
***
`page_registry` stores the original property that was passed in under
`supplied_<property>` and the coerced property under `<property>`.
For example, if this was called:
```
register_page(
'pages.historical_outlook',
name='Our historical view',
custom_key='custom value'
)
```
Then this will appear in `page_registry`:
```
OrderedDict([
(
'pages.historical_outlook',
dict(
module='pages.historical_outlook',
supplied_path=None,
path='/historical-outlook',
supplied_name='Our historical view',
name='Our historical view',
supplied_title=None,
title='Our historical view'
supplied_layout=None,
layout=<function pages.historical_outlook.layout>,
custom_key='custom value'
)
),
])
```
"""
if context_value.get().get("ignore_register_page"):
return
_validate.validate_use_pages(CONFIG)
page = dict(
module=_validate.validate_module_name(module),
supplied_path=path,
path_template=path_template,
path=path if path is not None else _infer_path(module, path_template),
supplied_name=name,
name=name if name is not None else _module_name_to_page_name(module),
)
page.update(
supplied_title=title,
title=title
if title is not None
else CONFIG.title
if CONFIG.title != "Dash"
else page["name"],
)
page.update(
description=description
if description
else CONFIG.description
if CONFIG.description
else "",
order=order,
supplied_order=order,
supplied_layout=layout,
**kwargs,
)
page.update(
supplied_image=image,
image=(image if image is not None else _infer_image(module)),
image_url=image_url,
)
page.update(redirect_from=_set_redirect(redirect_from, page["path"]))
PAGE_REGISTRY[module] = page
if page["path_template"]:
_validate.validate_template(page["path_template"])
if layout is not None:
# Override the layout found in the file set during `plug`
PAGE_REGISTRY[module]["layout"] = layout
# set home page order
order_supplied = any(
p["supplied_order"] is not None for p in PAGE_REGISTRY.values()
)
for p in PAGE_REGISTRY.values():
p["order"] = (
0 if p["path"] == "/" and not order_supplied else p["supplied_order"]
)
p["relative_path"] = get_relative_path(p["path"])
# Sort numeric orders first, then string orders, then no order,
# finally by module name for matching orders
for page in sorted(
PAGE_REGISTRY.values(),
key=lambda i: (
i["order"] is None, # False (order given) sorts before True
i["order"] if isinstance(i["order"], (int, float)) else float("inf"),
str(i["order"]),
i["module"],
),
):
PAGE_REGISTRY.move_to_end(page["module"])
def _path_to_page(path_id):
path_variables = None
for page in PAGE_REGISTRY.values():
if page["path_template"]:
template_id = page["path_template"].strip("/")
path_variables = _parse_path_variables(path_id, template_id)
if path_variables:
return page, path_variables
if path_id == page["path"].strip("/"):
return page, path_variables
return {}, None
def _page_meta_tags(app):
start_page, path_variables = _path_to_page(flask.request.path.strip("/"))
# use the supplied image_url or create url based on image in the assets folder
image = start_page.get("image", "")
if image:
image = app.get_asset_url(image)
assets_image_url = (
"".join([flask.request.url_root, image.lstrip("/")]) if image else None
)
supplied_image_url = start_page.get("image_url")
image_url = supplied_image_url if supplied_image_url else assets_image_url
title = start_page.get("title", app.title)
if callable(title):
title = title(**path_variables) if path_variables else title()
description = start_page.get("description", "")
if callable(description):
description = description(**path_variables) if path_variables else description()
return [
{"name": "description", "content": description},
{"property": "twitter:card", "content": "summary_large_image"},
{"property": "twitter:url", "content": flask.request.url},
{"property": "twitter:title", "content": title},
{"property": "twitter:description", "content": description},
{"property": "twitter:image", "content": image_url or ""},
{"property": "og:title", "content": title},
{"property": "og:type", "content": "website"},
{"property": "og:description", "content": description},
{"property": "og:image", "content": image_url or ""},
]
def _import_layouts_from_pages(pages_folder):
for root, dirs, files in os.walk(pages_folder):
dirs[:] = [d for d in dirs if not d.startswith(".") and not d.startswith("_")]
for file in files:
if file.startswith("_") or file.startswith(".") or not file.endswith(".py"):
continue
page_path = os.path.join(root, file)
with open(page_path, encoding="utf-8") as f:
content = f.read()
if "register_page" not in content:
continue
module_name = _infer_module_name(page_path)
spec = importlib.util.spec_from_file_location(module_name, page_path)
page_module = importlib.util.module_from_spec(spec) # type: ignore[reportArgumentType]
spec.loader.exec_module(page_module) # type: ignore[reportOptionalMemberAccess]
sys.modules[module_name] = page_module
if (
module_name in PAGE_REGISTRY
and not PAGE_REGISTRY[module_name]["supplied_layout"]
):
_validate.validate_pages_layout(module_name, page_module)
PAGE_REGISTRY[module_name]["layout"] = getattr(page_module, "layout")
+175
View File
@@ -0,0 +1,175 @@
from typing import List, Union, Optional, Any
def _operation(name, location, **kwargs):
return {"operation": name, "location": location, "params": kwargs}
_noop = object()
_KeyType = Union[str, int]
def validate_slice(obj: Any):
if isinstance(obj, slice):
raise TypeError("a slice is not a valid index for patch")
class Patch:
"""
Patch a callback output value
Act like a proxy of the output prop value on the frontend.
Supported prop types: Dictionaries and lists.
"""
def __init__(
self,
location: Optional[List[_KeyType]] = None,
parent: Optional["Patch"] = None,
):
if location is not None:
self._location = location
else:
# pylint: disable=consider-using-ternary
self._location = (parent and parent._location) or []
if parent is not None:
self._operations = parent._operations
else:
self._operations = []
def __getstate__(self):
return vars(self)
def __setstate__(self, state):
vars(self).update(state)
def __getitem__(self, item: _KeyType) -> "Patch":
validate_slice(item)
return Patch(location=self._location + [item], parent=self)
def __getattr__(self, item: _KeyType) -> "Patch":
if item == "tolist":
# to_json fix
raise AttributeError
if item == "_location":
return self._location # type: ignore
if item == "_operations":
return self._operations # type: ignore
return self.__getitem__(item)
def __setattr__(self, key: _KeyType, value: Any):
if key in ("_location", "_operations"):
self.__dict__[key] = value
else:
self.__setitem__(key, value)
def __delattr__(self, item: _KeyType):
self.__delitem__(item)
def __setitem__(self, key: _KeyType, value: Any):
validate_slice(key)
if value is _noop:
# The += set themselves.
return
self._operations.append(
_operation(
"Assign",
self._location + [key],
value=value,
)
)
def __delitem__(self, key: _KeyType):
validate_slice(key)
self._operations.append(_operation("Delete", self._location + [key]))
def __iadd__(self, other: Any):
if isinstance(other, (list, tuple)):
self.extend(other)
else:
self._operations.append(_operation("Add", self._location, value=other))
if not self._location:
return self
return _noop
def __isub__(self, other: Any):
self._operations.append(_operation("Sub", self._location, value=other))
if not self._location:
return self
return _noop
def __imul__(self, other: Any) -> "Patch":
self._operations.append(_operation("Mul", self._location, value=other))
if not self._location:
return self
return _noop
def __itruediv__(self, other: Any):
self._operations.append(_operation("Div", self._location, value=other))
if not self._location:
return self
return _noop
def __ior__(self, other: Any):
self.update(E=other)
if not self._location:
return self
return _noop
def __iter__(self):
raise TypeError("Patch objects are write-only, you cannot iterate them.")
def __repr__(self):
return f"<write-only dash.Patch object at {self._location}>"
def append(self, item: Any) -> None:
"""Add the item to the end of a list"""
self._operations.append(_operation("Append", self._location, value=item))
def prepend(self, item: Any) -> None:
"""Add the item to the start of a list"""
self._operations.append(_operation("Prepend", self._location, value=item))
def insert(self, index: int, item: Any) -> None:
"""Add the item at the index of a list"""
self._operations.append(
_operation("Insert", self._location, value=item, index=index)
)
def clear(self) -> None:
"""Remove all items in a list"""
self._operations.append(_operation("Clear", self._location))
def reverse(self) -> None:
"""Reversal of the order of items in a list"""
self._operations.append(_operation("Reverse", self._location))
def extend(self, item: Union[list, tuple]) -> None:
"""Add all the items to the end of a list"""
if not isinstance(item, (list, tuple)):
raise TypeError(f"{item} should be a list or tuple")
self._operations.append(_operation("Extend", self._location, value=item))
def remove(self, item: Any) -> None:
"""filter the item out of a list on the frontend"""
self._operations.append(_operation("Remove", self._location, value=item))
def update(self, E: Any = None, **F) -> None:
"""Merge a dict or keyword arguments with another dictionary"""
value = E or {}
value.update(F)
self._operations.append(_operation("Merge", self._location, value=value))
# pylint: disable=no-self-use
def sort(self):
raise KeyError(
"sort is reserved for future use, use brackets to access this key on your object"
)
def to_plotly_json(self) -> Any:
return {
"__dash_patch_update": "__dash_patch_update",
"operations": self._operations,
}
+319
View File
@@ -0,0 +1,319 @@
# -*- coding: utf-8 -*-
import shlex
import sys
import uuid
import hashlib
from collections import abc
import subprocess
import logging
import io
import json
import secrets
import string
import inspect
import re
from html import escape
from functools import wraps
from typing import Union
from .types import RendererHooks
logger = logging.getLogger()
def to_json(value):
# pylint: disable=import-outside-toplevel
from plotly.io.json import to_json_plotly
return to_json_plotly(value)
def interpolate_str(template, **data):
s = template
for k, v in data.items():
key = "{%" + k + "%}"
s = s.replace(key, v)
return s
def format_tag(
tag_name, attributes, inner="", closed=False, opened=False, sanitize=False
):
attributes = " ".join(
[f'{k}="{escape(v) if sanitize else v}"' for k, v in attributes.items()]
)
tag = f"<{tag_name} {attributes}"
if closed:
tag += "/>"
elif opened:
tag += ">"
else:
tag += ">" + inner + f"</{tag_name}>"
return tag
def generate_hash():
return str(uuid.uuid4().hex).strip("-")
# pylint: disable=no-member
def patch_collections_abc(member):
return getattr(abc, member)
class AttributeDict(dict):
"""Dictionary subclass enabling attribute lookup/assignment of keys/values.
For example::
>>> m = AttributeDict({'foo': 'bar'})
>>> m.foo
'bar'
>>> m.foo = 'not bar'
>>> m['foo']
'not bar'
``AttributeDict`` objects also provide ``.first()`` which acts like
``.get()`` but accepts multiple keys as arguments, and returns the value of
the first hit, e.g.::
>>> m = AttributeDict({'foo': 'bar', 'biz': 'baz'})
>>> m.first('wrong', 'incorrect', 'foo', 'biz')
'bar'
"""
def __setattr__(self, key, value):
self[key] = value
def __getattr__(self, key):
try:
return self[key]
except KeyError:
pass
# to conform with __getattr__ spec
# but get out of the except block so it doesn't look like a nested err
raise AttributeError(key)
def set_read_only(self, names, msg="Attribute is read-only"):
"""
Designate named attributes as read-only with the corresponding msg
Method is additive. Making additional calls to this method will update
existing messages and add to the current set of _read_only names.
"""
new_read_only = {name: msg for name in names}
if getattr(self, "_read_only", False):
self._read_only.update(new_read_only)
else:
object.__setattr__(self, "_read_only", new_read_only)
def finalize(self, msg="Object is final: No new keys may be added."):
"""Prevent any new keys being set."""
object.__setattr__(self, "_final", msg)
def __setitem__(self, key, val):
if key in self.__dict__.get("_read_only", {}):
raise AttributeError(self._read_only[key], key)
final_msg = self.__dict__.get("_final")
if final_msg and key not in self:
raise AttributeError(final_msg, key)
return super().__setitem__(key, val)
def update(self, other=None, **kwargs):
# Overrides dict.update() to use __setitem__ above
# Needs default `None` and `kwargs` to satisfy type checking
source = other if other is not None else kwargs
for k, v in source.items():
self[k] = v
# pylint: disable=inconsistent-return-statements
def first(self, *names):
for name in names:
value = self.get(name)
if value:
return value
if not names:
return next(iter(self), {})
def create_callback_id(output, inputs, no_output=False):
# A single dot within a dict id key or value is OK
# but in case of multiple dots together escape each dot
# with `\` so we don't mistake it for multi-outputs
hashed_inputs = None
def _hash_inputs():
return hashlib.sha256(
".".join(str(x) for x in inputs).encode("utf-8")
).hexdigest()
def _concat(x):
nonlocal hashed_inputs
_id = x.component_id_str().replace(".", "\\.") + "." + x.component_property
if x.allow_duplicate:
if not hashed_inputs:
hashed_inputs = _hash_inputs()
# Actually adds on the property part.
_id += f"@{hashed_inputs}"
return _id
if no_output:
# No output will hash the inputs.
return _hash_inputs()
if isinstance(output, (list, tuple)):
return ".." + "...".join(_concat(x) for x in output) + ".."
return _concat(output)
# inverse of create_callback_id - should only be relevant if an old renderer is
# hooked up to a new back end, which will only happen in special cases like
# embedded
def split_callback_id(callback_id):
if callback_id.startswith(".."):
return [split_callback_id(oi) for oi in callback_id[2:-2].split("...")]
id_, prop = callback_id.rsplit(".", 1)
return {"id": id_, "property": prop}
def stringify_id(id_) -> str:
def _json(k, v):
vstr = v.to_json() if hasattr(v, "to_json") else json.dumps(v)
return f"{json.dumps(k)}:{vstr}"
if isinstance(id_, dict):
return "{" + ",".join(_json(k, id_[k]) for k in sorted(id_)) + "}"
return id_
def inputs_to_dict(inputs_list):
inputs = AttributeDict()
for i in inputs_list:
inputsi = i if isinstance(i, list) else [i]
for ii in inputsi:
id_str = stringify_id(ii["id"])
inputs[f'{id_str}.{ii["property"]}'] = ii.get("value")
return inputs
def convert_to_AttributeDict(nested_list):
new_dict = []
for i in nested_list:
if isinstance(i, dict):
new_dict.append(AttributeDict(i))
else:
new_dict.append([AttributeDict(ii) for ii in i])
return new_dict
def inputs_to_vals(inputs):
return [
[ii.get("value") for ii in i] if isinstance(i, list) else i.get("value")
for i in inputs
]
def run_command_with_process(cmd):
is_win = sys.platform == "win32"
with subprocess.Popen(shlex.split(cmd, posix=is_win), shell=is_win) as proc:
proc.wait()
if proc.poll() is None:
logger.warning("🚨 trying to terminate subprocess in safe way")
try:
proc.communicate()
except Exception: # pylint: disable=broad-except
logger.exception("🚨 first try communicate failed")
proc.kill()
proc.communicate()
def compute_hash(path):
with io.open(path, encoding="utf-8") as fp:
return hashlib.sha256(fp.read().encode("utf-8")).hexdigest()
def job(msg=""):
def wrapper(func):
@wraps(func)
def _wrapper(*args, **kwargs):
logger.info("🏗️ [%s] 🏗️ - %s", func.__name__, msg)
res = func(*args, **kwargs)
logger.info("::: 🍻🍻🍻 [%s] job done 🍻🍻🍻 :::", func.__name__)
return res
return _wrapper
return wrapper
def gen_salt(chars):
return "".join(
secrets.choice(string.ascii_letters + string.digits) for _ in range(chars)
)
class OrderedSet(abc.MutableSet):
def __init__(self, *args):
self._data = []
for i in args:
self.add(i)
def add(self, value):
if value not in self._data:
self._data.append(value)
def discard(self, value):
self._data.remove(value)
def __contains__(self, x):
return x in self._data
def __len__(self):
return len(self._data)
def __iter__(self):
for i in self._data:
yield i
def coerce_to_list(obj):
if not isinstance(obj, (list, tuple)):
return [obj]
return obj
def clean_property_name(name: str):
return name.split("@")[0]
def hooks_to_js_object(hooks: Union[RendererHooks, None]) -> str:
if hooks is None:
return ""
hook_str = ",".join(f"{key}: {val}" for key, val in hooks.items())
return f"{{{hook_str}}}"
def parse_version(version):
return tuple(int(s) for s in version.split("."))
def get_caller_name():
stack = inspect.stack()
for s in stack:
if s.function == "<module>":
return s.frame.f_locals.get("__name__", "__main__")
return "__main__"
def pascal_case(name: Union[str, None]):
s = re.sub(r"\s", "_", str(name))
# Replace leading `_`
s = re.sub("^[_]+", "", s)
if not s:
return s
return s[0].upper() + re.sub(
r"[\-_\.]+([a-z])", lambda match: match.group(1).upper(), s[1:]
)
@@ -0,0 +1,587 @@
import sys
from collections.abc import MutableSequence
import re
from textwrap import dedent
from keyword import iskeyword
import flask
from ._grouping import grouping_len, map_grouping
from ._no_update import NoUpdate
from .development.base_component import Component
from . import exceptions
from ._utils import (
patch_collections_abc,
stringify_id,
to_json,
coerce_to_list,
clean_property_name,
)
def validate_callback(outputs, inputs, state, extra_args, types):
Input, Output, State = types
if extra_args:
if not isinstance(extra_args[0], (Output, Input, State)):
raise exceptions.IncorrectTypeException(
dedent(
f"""
Callback arguments must be `Output`, `Input`, or `State` objects,
optionally wrapped in a list or tuple. We found (possibly after
unwrapping a list or tuple):
{repr(extra_args[0])}
"""
)
)
raise exceptions.IncorrectTypeException(
dedent(
f"""
In a callback definition, you must provide all Outputs first,
then all Inputs, then all States. After this item:
{(outputs + inputs + state)[-1]!r}
we found this item next:
{extra_args[0]!r}
"""
)
)
for args in [outputs, inputs, state]:
for arg in args:
validate_callback_arg(arg)
def validate_callback_arg(arg):
if not isinstance(getattr(arg, "component_property", None), str):
raise exceptions.IncorrectTypeException(
dedent(
f"""
component_property must be a string, found {arg.component_property!r}
"""
)
)
if hasattr(arg, "component_event"):
raise exceptions.NonExistentEventException(
"""
Events have been removed.
Use the associated property instead.
"""
)
if isinstance(arg.component_id, dict):
validate_id_dict(arg)
elif isinstance(arg.component_id, str):
validate_id_string(arg)
else:
raise exceptions.IncorrectTypeException(
dedent(
f"""
component_id must be a string or dict, found {arg.component_id!r}
"""
)
)
def validate_id_dict(arg):
arg_id = arg.component_id
for k in arg_id:
# Need to keep key type validation on the Python side, since
# non-string keys will be converted to strings in json.dumps and may
# cause unwanted collisions
if not isinstance(k, str):
raise exceptions.IncorrectTypeException(
dedent(
f"""
Wildcard ID keys must be non-empty strings,
found {k!r} in id {arg_id!r}
"""
)
)
def validate_id_string(arg):
arg_id = arg.component_id
invalid_chars = ".{"
invalid_found = [x for x in invalid_chars if x in arg_id]
if invalid_found:
raise exceptions.InvalidComponentIdError(
f"""
The element `{arg_id}` contains `{"`, `".join(invalid_found)}` in its ID.
Characters `{"`, `".join(invalid_chars)}` are not allowed in IDs.
"""
)
def validate_output_spec(output, output_spec, Output):
"""
This validation is for security and internal debugging, not for users,
so the messages are not intended to be clear.
`output` comes from the callback definition, `output_spec` from the request.
"""
if not isinstance(output, (list, tuple)):
output, output_spec = [output], [output_spec]
elif len(output) != len(output_spec):
raise exceptions.CallbackException("Wrong length output_spec")
for outi, speci in zip(output, output_spec):
speci_list = speci if isinstance(speci, (list, tuple)) else [speci]
for specij in speci_list:
if (
not Output(specij["id"], clean_property_name(specij["property"]))
== outi
):
raise exceptions.CallbackException(
"Output does not match callback definition"
)
def validate_and_group_input_args(flat_args, arg_index_grouping):
if grouping_len(arg_index_grouping) != len(flat_args):
raise exceptions.CallbackException("Inputs do not match callback definition")
args_grouping = map_grouping(lambda ind: flat_args[ind], arg_index_grouping)
if isinstance(arg_index_grouping, dict):
func_args = []
func_kwargs = args_grouping
for key in func_kwargs:
if not key.isidentifier():
raise exceptions.CallbackException(
f"{key} is not a valid Python variable name"
)
elif isinstance(arg_index_grouping, (tuple, list)):
func_args = list(args_grouping)
func_kwargs = {}
else:
# Scalar input
func_args = [args_grouping]
func_kwargs = {}
return func_args, func_kwargs
def validate_multi_return(output_lists, output_values, callback_id):
if not isinstance(output_values, (list, tuple)):
raise exceptions.InvalidCallbackReturnValue(
dedent(
f"""
The callback {callback_id} is a multi-output.
Expected the output type to be a list or tuple but got:
{output_values!r}.
"""
)
)
if len(output_values) != len(output_lists):
raise exceptions.InvalidCallbackReturnValue(
f"""
Invalid number of output values for {callback_id}.
Expected {len(output_lists)}, got {len(output_values)}
"""
)
for i, output_spec in enumerate(output_lists):
if isinstance(output_spec, list):
output_value = output_values[i]
if not isinstance(output_value, (list, tuple)):
raise exceptions.InvalidCallbackReturnValue(
dedent(
f"""
The callback {callback_id} output {i} is a wildcard multi-output.
Expected the output type to be a list or tuple but got:
{output_value!r}.
output spec: {output_spec!r}
"""
)
)
if len(output_value) != len(output_spec):
raise exceptions.InvalidCallbackReturnValue(
dedent(
f"""
Invalid number of output values for {callback_id} item {i}.
Expected {len(output_spec)}, got {len(output_value)}
output spec: {output_spec!r}
output value: {output_value!r}
"""
)
)
def fail_callback_output(output_value, output):
valid_children = (str, int, float, type(None), Component, NoUpdate)
valid_props = (str, int, float, type(None), tuple, MutableSequence, NoUpdate)
def _raise_invalid(bad_val, outer_val, path, index=None, toplevel=False):
bad_type = type(bad_val).__name__
outer_id = f"(id={outer_val.id:s})" if getattr(outer_val, "id", False) else ""
outer_type = type(outer_val).__name__
if toplevel:
location = dedent(
"""
The value in question is either the only value returned,
or is in the top level of the returned list,
"""
)
else:
index_string = "[*]" if index is None else f"[{index:d}]"
location = dedent(
f"""
The value in question is located at
{index_string} {outer_type} {outer_id}
{path},
"""
)
obj = "tree with one value" if not toplevel else "value"
raise exceptions.InvalidCallbackReturnValue(
dedent(
f"""
The callback for `{output!r}`
returned a {obj:s} having type `{bad_type}`
which is not JSON serializable.
{location}
and has string representation
`{bad_val}`
In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.
"""
)
)
def _valid_child(val):
return isinstance(val, valid_children)
def _valid_prop(val):
return isinstance(val, valid_props)
def _can_serialize(val):
if not (_valid_child(val) or _valid_prop(val)):
return False
try:
to_json(val)
except TypeError:
return False
return True
def _validate_value(val, index=None):
# val is a Component
if isinstance(val, Component):
unserializable_items = []
# pylint: disable=protected-access
for p, j in val._traverse_with_paths():
# check each component value in the tree
if not _valid_child(j):
_raise_invalid(bad_val=j, outer_val=val, path=p, index=index)
if not _can_serialize(j):
# collect unserializable items separately, so we can report
# only the deepest level, not all the parent components that
# are just unserializable because of their children.
unserializable_items = [
i for i in unserializable_items if not p.startswith(i[0])
]
if unserializable_items:
# we already have something unserializable in a different
# branch - time to stop and fail
break
if all(not i[0].startswith(p) for i in unserializable_items):
unserializable_items.append((p, j))
# Children that are not of type Component or
# list/tuple not returned by traverse
child = getattr(j, "children", None)
if not isinstance(child, (tuple, MutableSequence)):
if child and not _can_serialize(child):
_raise_invalid(
bad_val=child,
outer_val=val,
path=p + "\n" + "[*] " + type(child).__name__,
index=index,
)
if unserializable_items:
p, j = unserializable_items[0]
# just report the first one, even if there are multiple,
# as that's how all the other errors work
_raise_invalid(bad_val=j, outer_val=val, path=p, index=index)
# Also check the child of val, as it will not be returned
child = getattr(val, "children", None)
if not isinstance(child, (tuple, MutableSequence)):
if child and not _can_serialize(val):
_raise_invalid(
bad_val=child,
outer_val=val,
path=type(child).__name__,
index=index,
)
if not _can_serialize(val):
_raise_invalid(
bad_val=val,
outer_val=type(val).__name__,
path="",
index=index,
toplevel=True,
)
if isinstance(output_value, list):
for i, val in enumerate(output_value):
_validate_value(val, index=i)
else:
_validate_value(output_value)
# if we got this far, raise a generic JSON error
raise exceptions.InvalidCallbackReturnValue(
f"""
The callback for output `{output!r}`
returned a value which is not JSON serializable.
In general, Dash properties can only be dash components, strings,
dictionaries, numbers, None, or lists of those.
"""
)
def check_obsolete(kwargs):
for key in kwargs:
if key in ["components_cache_max_age", "static_folder"]:
raise exceptions.ObsoleteKwargException(
f"""
{key} is no longer a valid keyword argument in Dash since v1.0.
See https://dash.plotly.com for details.
"""
)
if key in ["dynamic_loading", "preloaded_libraries"]:
# Only warns as this was only available for a short time.
print(
f"{key} has been removed and no longer a valid keyword argument in Dash.",
file=sys.stderr,
)
continue
if key in ["long_callback_manager"]:
raise exceptions.ObsoleteKwargException(
"long_callback_manager is obsolete, use background_callback_manager instead"
)
# any other kwarg mimic the built-in exception
raise TypeError(f"Dash() got an unexpected keyword argument '{key}'")
def validate_js_path(registered_paths, package_name, path_in_package_dist):
if package_name not in registered_paths:
raise exceptions.DependencyException(
f"""
Error loading dependency. "{package_name}" is not a registered library.
Registered libraries are:
{list(registered_paths.keys())}
"""
)
if path_in_package_dist not in registered_paths[package_name]:
raise exceptions.DependencyException(
f"""
"{package_name}" is registered but the path requested is not valid.
The path requested: "{path_in_package_dist}"
List of registered paths: {registered_paths}
"""
)
def validate_index(name, checks, index):
missing = [i for check, i in checks if not re.compile(check).search(index)]
if missing:
plural = "s" if len(missing) > 1 else ""
raise exceptions.InvalidIndexException(
f"Missing item{plural} {', '.join(missing)} in {name}."
)
def validate_layout_type(value):
if not isinstance(
value, (Component, patch_collections_abc("Callable"), list, tuple)
):
raise exceptions.NoLayoutException(
"""
Layout must be a single dash component, a list of dash components,
or a function that returns a dash component.
"""
)
def validate_layout(layout, layout_value):
if layout is None:
raise exceptions.NoLayoutException(
"""
The layout was `None` at the time that `run` was called.
Make sure to set the `layout` attribute of your application
before running the server.
"""
)
component_ids = set()
def _validate(value):
def _validate_id(comp):
component_id = stringify_id(getattr(comp, "id", None))
if component_id and component_id in component_ids:
raise exceptions.DuplicateIdError(
f"""
Duplicate component id found in the initial layout: `{component_id}`
"""
)
component_ids.add(component_id)
_validate_id(value)
for component in value._traverse(): # pylint: disable=protected-access
_validate_id(component)
if isinstance(layout_value, (list, tuple)):
for component in layout_value:
if isinstance(component, (str,)):
continue
if isinstance(component, (Component,)):
_validate(component)
else:
raise exceptions.NoLayoutException(
"Only strings and components are allowed in a list layout."
)
else:
_validate(layout_value)
def validate_template(template):
variable_names = re.findall("<(.*?)>", template)
for name in variable_names:
if not name.isidentifier() or iskeyword(name):
raise Exception(
f'`{name}` is not a valid Python variable name in `path_template`: "{template}".'
)
def check_for_duplicate_pathnames(registry):
path_to_module = {}
for page in registry.values():
if page["path"] not in path_to_module:
path_to_module[page["path"]] = [page["module"]]
else:
path_to_module[page["path"]].append(page["module"])
for modules in path_to_module.values():
if len(modules) > 1:
raise Exception(f"modules {modules} have duplicate paths")
def validate_registry(registry):
for page in registry.values():
if "layout" not in page:
raise exceptions.NoLayoutException(
f"No layout in module `{page['module']}` in dash.page_registry"
)
if page["module"] == "__main__":
raise Exception(
"""
When registering pages from app.py, `__name__` is not a valid module name. Use a string instead.
For example, `dash.register_page("my_module_name")`, rather than `dash.register_page(__name__)`
"""
)
def validate_pages_layout(module, page):
if not hasattr(page, "layout"):
raise exceptions.NoLayoutException(
f"""
No layout found in module {module}
A variable or a function named "layout" is required.
"""
)
def validate_use_pages(config):
if not config.get("assets_folder", None):
raise exceptions.PageError(
"`dash.register_page()` must be called after app instantiation"
)
if flask.has_request_context():
raise exceptions.PageError(
"""
dash.register_page() cant be called within a callback as it updates dash.page_registry, which is a global variable.
For more details, see https://dash.plotly.com/sharing-data-between-callbacks#why-global-variables-will-break-your-app
"""
)
def validate_module_name(module):
if not isinstance(module, str):
raise exceptions.PageError(
"The first attribute of dash.register_page() must be a string or '__name__'"
)
return module
def validate_background_callbacks(callback_map):
# Validate that background callback side output & inputs are not circular
# If circular, triggering a background callback would result in a fatal server/computer crash.
all_outputs = set()
input_indexed = {}
for callback in callback_map.values():
out = coerce_to_list(callback["output"])
all_outputs.update(out)
for o in out:
input_indexed.setdefault(o, set())
input_indexed[o].update(coerce_to_list(callback["raw_inputs"]))
for callback in (x for x in callback_map.values() if x.get("background")):
bg_info = callback["background"]
progress = bg_info.get("progress", [])
running = bg_info.get("running", [])
bg_inputs = coerce_to_list(callback["raw_inputs"])
outputs = set([x[0] for x in running] + progress)
circular = [
x
for x in set(k for k, v in input_indexed.items() if v.intersection(outputs))
if x in bg_inputs
]
if circular:
raise exceptions.BackgroundCallbackError(
f"Background callback circular error!\n{circular} is used as input for a background callback"
f" but also used as output from an input that is updated with progress or running argument."
)
def validate_duplicate_output(
output, prevent_initial_call, config_prevent_initial_call
):
if "initial_duplicate" in (prevent_initial_call, config_prevent_initial_call):
return
def _valid(out):
if (
out.allow_duplicate
and not prevent_initial_call
and not config_prevent_initial_call
):
raise exceptions.DuplicateCallback(
"allow_duplicate requires prevent_initial_call to be True. The order of the call is not"
" guaranteed to be the same on every page load. "
"To enable duplicate callback with initial call, set prevent_initial_call='initial_duplicate' "
" or globally in the config prevent_initial_callbacks='initial_duplicate'"
)
if isinstance(output, (list, tuple)):
for o in output:
_valid(o)
return
_valid(output)
@@ -0,0 +1,36 @@
import collections
import os
import re
import time
def watch(folders, on_change, pattern=None, sleep_time=0.1):
pattern = re.compile(pattern) if pattern else None
watched = collections.defaultdict(lambda: -1.0)
def walk():
walked = []
for folder in folders:
for current, _, files in os.walk(folder):
for f in files:
if pattern and not pattern.search(f):
continue
path = os.path.join(current, f)
info = os.stat(path)
new_time = info.st_mtime
if new_time > watched[path] > 0:
on_change(path, new_time, False)
watched[path] = new_time
walked.append(path)
# Look for deleted files
for w in [x for x in watched.keys() if x not in walked]:
del watched[w]
on_change(w, -1, True)
while True:
walk()
time.sleep(sleep_time)
@@ -0,0 +1,6 @@
from .managers.celery_manager import ( # noqa: F401,E402
CeleryManager,
)
from .managers.diskcache_manager import ( # noqa: F401,E402
DiskcacheManager,
)
@@ -0,0 +1,18 @@
class ProxySetProps(dict):
"""
Defer dictionary item setter to run a custom function on change.
Used by background callback manager to save the `set_props` data.
"""
def __init__(self, on_change):
super().__init__()
self.on_change = on_change
self._data = {}
def __setitem__(self, key, value):
self.on_change(key, value)
self._data.setdefault(key, {})
self._data[key] = {**self._data[key], **value}
def get(self, key, default=None):
return self._data.get(key, default)
@@ -0,0 +1,117 @@
from abc import ABC
import inspect
import hashlib
class BaseBackgroundCallbackManager(ABC):
UNDEFINED = object()
# Keep a ref to all the ref to register every callback to every manager.
managers = []
# Keep every function for late registering.
functions = []
def __init__(self, cache_by):
if cache_by is not None and not isinstance(cache_by, list):
cache_by = [cache_by]
self.cache_by = cache_by
BaseBackgroundCallbackManager.managers.append(self)
self.func_registry = {}
# Register all funcs that were added before instantiation.
# Ensure all celery task are registered.
for fdetails in self.functions:
self.register(*fdetails)
def terminate_job(self, job):
raise NotImplementedError
def terminate_unhealthy_job(self, job):
raise NotImplementedError
def job_running(self, job):
raise NotImplementedError
def make_job_fn(self, fn, progress, key=None):
raise NotImplementedError
def call_job_fn(self, key, job_fn, args, context):
raise NotImplementedError
def get_progress(self, key):
raise NotImplementedError
def result_ready(self, key):
raise NotImplementedError
def get_result(self, key, job):
raise NotImplementedError
def get_updated_props(self, key):
raise NotImplementedError
def build_cache_key(self, fn, args, cache_args_to_ignore, triggered):
fn_source = inspect.getsource(fn)
if not isinstance(cache_args_to_ignore, (list, tuple)):
cache_args_to_ignore = [cache_args_to_ignore]
if cache_args_to_ignore:
if isinstance(args, dict):
args = {k: v for k, v in args.items() if k not in cache_args_to_ignore}
else:
args = [
arg for i, arg in enumerate(args) if i not in cache_args_to_ignore
]
hash_dict = dict(args=args, fn_source=fn_source, triggered=triggered)
if self.cache_by is not None:
# Caching enabled
for i, cache_item in enumerate(self.cache_by):
# Call cache function
hash_dict[f"cache_key_{i}"] = cache_item()
return hashlib.sha256(str(hash_dict).encode("utf-8")).hexdigest()
def register(self, key, fn, progress):
self.func_registry[key] = self.make_job_fn(fn, progress, key)
@staticmethod
def register_func(fn, progress, callback_id):
key = BaseBackgroundCallbackManager.hash_function(fn, callback_id)
BaseBackgroundCallbackManager.functions.append(
(
key,
fn,
progress,
)
)
for manager in BaseBackgroundCallbackManager.managers:
manager.register(key, fn, progress)
return key
@staticmethod
def _make_progress_key(key):
return key + "-progress"
@staticmethod
def _make_set_props_key(key):
return f"{key}-set_props"
@staticmethod
def hash_function(fn, callback_id=""):
try:
fn_source = inspect.getsource(fn)
fn_str = fn_source
except OSError: # pylint: disable=too-broad-exception
fn_str = getattr(fn, "__name__", "")
return hashlib.sha256(
callback_id.encode("utf-8") + fn_str.encode("utf-8")
).hexdigest()
@@ -0,0 +1,263 @@
import json
import traceback
from contextvars import copy_context
import asyncio
from functools import partial
from _plotly_utils.utils import PlotlyJSONEncoder
from dash._callback_context import context_value
from dash._utils import AttributeDict
from dash.exceptions import PreventUpdate
from dash.background_callback._proxy_set_props import ProxySetProps
from dash.background_callback.managers import BaseBackgroundCallbackManager
class CeleryManager(BaseBackgroundCallbackManager):
"""Manage background execution of callbacks with a celery queue."""
def __init__(self, celery_app, cache_by=None, expire=None):
"""
Background callback manager that runs callback logic on a celery task queue,
and stores results using a celery result backend.
:param celery_app:
A celery.Celery application instance that must be configured with a
result backend. See the celery documentation for information on
configuration options.
:param cache_by:
A list of zero-argument functions. When provided, caching is enabled and
the return values of these functions are combined with the callback
function's input arguments, triggered inputs and source code to generate cache keys.
:param expire:
If provided, a cache entry will be removed when it has not been accessed
for ``expire`` seconds. If not provided, the lifetime of cache entries
is determined by the default behavior of the celery result backend.
"""
try:
import celery # type: ignore[reportMissingImports]; pylint: disable=import-outside-toplevel,import-error
from celery.backends.base import ( # type: ignore[reportMissingImports]; pylint: disable=import-outside-toplevel,import-error
DisabledBackend,
)
except ImportError as missing_imports:
raise ImportError(
"""\
CeleryManager requires extra dependencies which can be installed doing
$ pip install "dash[celery]"\n"""
) from missing_imports
if not isinstance(celery_app, celery.Celery):
raise ValueError("First argument must be a celery.Celery object")
if isinstance(celery_app.backend, DisabledBackend):
raise ValueError("Celery instance must be configured with a result backend")
self.handle = celery_app
self.expire = expire
super().__init__(cache_by)
def terminate_job(self, job):
if job is None:
return
self.handle.control.terminate(job)
def terminate_unhealthy_job(self, job):
task = self.get_task(job)
if task and task.status in ("FAILURE", "REVOKED"):
return self.terminate_job(job)
return False
def job_running(self, job):
future = self.get_task(job)
return future and future.status in (
"PENDING",
"RECEIVED",
"STARTED",
"RETRY",
"PROGRESS",
)
def make_job_fn(self, fn, progress, key=None):
return _make_job_fn(fn, self.handle, progress, key)
def get_task(self, job):
if job:
return self.handle.AsyncResult(job)
return None
def clear_cache_entry(self, key):
self.handle.backend.delete(key)
def call_job_fn(self, key, job_fn, args, context):
task = job_fn.delay(key, self._make_progress_key(key), args, context)
return task.task_id
def get_progress(self, key):
progress_key = self._make_progress_key(key)
progress_data = self.handle.backend.get(progress_key)
if progress_data:
self.handle.backend.delete(progress_key)
return json.loads(progress_data)
return None
def result_ready(self, key):
return self.handle.backend.get(key) is not None
def get_result(self, key, job):
# Get result value
result = self.handle.backend.get(key)
if result is None:
return self.UNDEFINED
result = json.loads(result)
# Clear result if not caching
if self.cache_by is None:
self.clear_cache_entry(key)
else:
if self.expire:
# Set/update expiration time
self.handle.backend.expire(key, self.expire)
self.clear_cache_entry(self._make_progress_key(key))
self.terminate_job(job)
return result
def get_updated_props(self, key):
updated_props = self.handle.backend.get(self._make_set_props_key(key))
if updated_props is None:
return {}
self.clear_cache_entry(key)
return json.loads(updated_props)
def _make_job_fn(fn, celery_app, progress, key): # pylint: disable=too-many-statements
cache = celery_app.backend
@celery_app.task(name=f"background_callback_{key}")
def job_fn(
result_key, progress_key, user_callback_args, context=None
): # pylint: disable=too-many-statements
def _set_progress(progress_value):
if not isinstance(progress_value, (list, tuple)):
progress_value = [progress_value]
cache.set(progress_key, json.dumps(progress_value, cls=PlotlyJSONEncoder))
maybe_progress = [_set_progress] if progress else []
def _set_props(_id, props):
cache.set(
f"{result_key}-set_props",
json.dumps({_id: props}, cls=PlotlyJSONEncoder),
)
ctx = copy_context()
def run():
c = AttributeDict(**context) # type: ignore[reportCallIssue]
c.ignore_register_page = False
c.updated_props = ProxySetProps(_set_props)
context_value.set(c)
errored = False
user_callback_output = None # to help type checking
try:
if isinstance(user_callback_args, dict):
user_callback_output = fn(*maybe_progress, **user_callback_args)
elif isinstance(user_callback_args, (list, tuple)):
user_callback_output = fn(*maybe_progress, *user_callback_args)
else:
user_callback_output = fn(*maybe_progress, user_callback_args)
except PreventUpdate:
# Put NoUpdate dict directly to avoid circular imports.
errored = True
cache.set(
result_key,
json.dumps(
{"_dash_no_update": "_dash_no_update"}, cls=PlotlyJSONEncoder
),
)
except Exception as err: # pylint: disable=broad-except
errored = True
cache.set(
result_key,
json.dumps(
{
"background_callback_error": {
"msg": str(err),
"tb": traceback.format_exc(),
}
},
),
)
if not errored:
cache.set(
result_key, json.dumps(user_callback_output, cls=PlotlyJSONEncoder)
)
async def async_run():
c = AttributeDict(**context)
c.ignore_register_page = False
c.updated_props = ProxySetProps(_set_props)
context_value.set(c)
errored = False
try:
if isinstance(user_callback_args, dict):
user_callback_output = await fn(
*maybe_progress, **user_callback_args
)
elif isinstance(user_callback_args, (list, tuple)):
user_callback_output = await fn(
*maybe_progress, *user_callback_args
)
else:
user_callback_output = await fn(*maybe_progress, user_callback_args)
except PreventUpdate:
# Put NoUpdate dict directly to avoid circular imports.
errored = True
cache.set(
result_key,
json.dumps(
{"_dash_no_update": "_dash_no_update"}, cls=PlotlyJSONEncoder
),
)
except Exception as err: # pylint: disable=broad-except
errored = True
cache.set(
result_key,
json.dumps(
{
"background_callback_error": {
"msg": str(err),
"tb": traceback.format_exc(),
}
},
),
)
if asyncio.iscoroutine(user_callback_output):
user_callback_output = await user_callback_output
if not errored:
cache.set(
result_key, json.dumps(user_callback_output, cls=PlotlyJSONEncoder)
)
if asyncio.iscoroutinefunction(fn):
func = partial(ctx.run, async_run)
asyncio.run(func())
else:
ctx.run(run)
return job_fn
class CeleryLongCallbackManager(CeleryManager):
"""Deprecated: use `from dash import CeleryManager` instead."""
@@ -0,0 +1,305 @@
import traceback
from contextvars import copy_context
import asyncio
from functools import partial
from . import BaseBackgroundCallbackManager
from .._proxy_set_props import ProxySetProps
from ..._callback_context import context_value
from ..._utils import AttributeDict
from ...exceptions import PreventUpdate
_pending_value = "__$pending__"
class DiskcacheManager(BaseBackgroundCallbackManager):
"""Manage the background execution of callbacks with subprocesses and a diskcache result backend."""
def __init__(self, cache=None, cache_by=None, expire=None):
"""
Background callback manager that runs callback logic in a subprocess and stores
results on disk using diskcache
:param cache:
A diskcache.Cache or diskcache.FanoutCache instance. See the diskcache
documentation for information on configuration options. If not provided,
a diskcache.Cache instance will be created with default values.
:param cache_by:
A list of zero-argument functions. When provided, caching is enabled and
the return values of these functions are combined with the callback
function's input arguments, triggered inputs and source code to generate cache keys.
:param expire:
If provided, a cache entry will be removed when it has not been accessed
for ``expire`` seconds. If not provided, the lifetime of cache entries
is determined by the default behavior of the ``cache`` instance.
"""
try:
import diskcache # type: ignore[reportMissingImports]; pylint: disable=import-outside-toplevel
import psutil # noqa: F401,E402 pylint: disable=import-outside-toplevel,unused-import,unused-variable,import-error
import multiprocess # noqa: F401,E402 pylint: disable=import-outside-toplevel,unused-import,unused-variable
except ImportError as missing_imports:
raise ImportError(
"""\
DiskcacheManager requires extra dependencies which can be installed doing
$ pip install "dash[diskcache]"\n"""
) from missing_imports
if cache is None:
self.handle = diskcache.Cache()
else:
if not isinstance(cache, (diskcache.Cache, diskcache.FanoutCache)):
raise ValueError(
"First argument must be a diskcache.Cache "
"or diskcache.FanoutCache object"
)
self.handle = cache
self.expire = expire
super().__init__(cache_by)
def terminate_job(self, job):
import psutil # pylint: disable=import-outside-toplevel,import-error
if job is None:
return
job = int(job)
# Use diskcache transaction so multiple process don't try to kill the
# process at the same time
with self.handle.transact():
if psutil.pid_exists(job):
process = psutil.Process(job)
for proc in process.children(recursive=True):
try:
proc.kill()
except psutil.NoSuchProcess:
pass
try:
process.kill()
except psutil.NoSuchProcess:
pass
try:
process.wait(1)
except (psutil.TimeoutExpired, psutil.NoSuchProcess):
pass
def terminate_unhealthy_job(self, job):
import psutil # pylint: disable=import-outside-toplevel,import-error
job = int(job)
if job and psutil.pid_exists(job):
if not self.job_running(job):
self.terminate_job(job)
return True
return False
def job_running(self, job):
import psutil # pylint: disable=import-outside-toplevel,import-error
job = int(job)
if job and psutil.pid_exists(job):
proc = psutil.Process(job)
return proc.status() != psutil.STATUS_ZOMBIE
return False
def make_job_fn(self, fn, progress, key=None):
return _make_job_fn(fn, self.handle, progress)
def clear_cache_entry(self, key):
self.handle.delete(key)
# noinspection PyUnresolvedReferences
def call_job_fn(self, key, job_fn, args, context):
"""
Call the job function, supporting both sync and async jobs.
Args:
key: Cache key for the job.
job_fn: The job function to execute.
args: Arguments for the job function.
context: Context for the job.
Returns:
The PID of the spawned process or None for async execution.
"""
# pylint: disable-next=import-outside-toplevel,no-name-in-module,import-error
from multiprocess import Process # type: ignore
# pylint: disable-next=not-callable
process = Process(
target=job_fn,
args=(key, self._make_progress_key(key), args, context),
)
process.start()
return process.pid
@staticmethod
def _run_async_in_process(job_fn, key, args, context):
"""
Helper function to run an async job in a new process.
Args:
job_fn: The async job function.
key: Cache key for the job.
args: Arguments for the job function.
context: Context for the job.
"""
# Create a new event loop for the process
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# Wrap the job function to include key and progress
async_job = partial(job_fn, key, args, context)
try:
# Run the async job and wait for completion
loop.run_until_complete(async_job())
except Exception as e:
# Handle errors, log them, and cache if necessary
raise Exception(str(e)) from e
finally:
loop.close()
def get_progress(self, key):
progress_key = self._make_progress_key(key)
progress_data = self.handle.get(progress_key)
if progress_data:
self.handle.delete(progress_key)
return progress_data
def result_ready(self, key):
return self.handle.get(key) is not None
def get_result(self, key, job):
# Get result value
result = self.handle.get(key, self.UNDEFINED)
if result is self.UNDEFINED:
return self.UNDEFINED
# Clear result if not caching
if self.cache_by is None:
self.clear_cache_entry(key)
else:
if self.expire:
self.handle.touch(key, expire=self.expire)
self.clear_cache_entry(self._make_progress_key(key))
if job:
self.terminate_job(job)
return result
def get_updated_props(self, key):
set_props_key = self._make_set_props_key(key)
result = self.handle.get(set_props_key, self.UNDEFINED)
if result is self.UNDEFINED:
return {}
self.clear_cache_entry(set_props_key)
return result
# pylint: disable-next=too-many-statements
def _make_job_fn(fn, cache, progress):
# pylint: disable-next=too-many-statements
def job_fn(result_key, progress_key, user_callback_args, context):
def _set_progress(progress_value):
if not isinstance(progress_value, (list, tuple)):
progress_value = [progress_value]
cache.set(progress_key, progress_value)
maybe_progress = [_set_progress] if progress else []
def _set_props(_id, props):
cache.set(f"{result_key}-set_props", {_id: props})
ctx = copy_context()
def run():
c = AttributeDict(**context)
c.ignore_register_page = False
c.updated_props = ProxySetProps(_set_props)
context_value.set(c)
errored = False
user_callback_output = None # initialized to prevent type checker warnings
try:
if isinstance(user_callback_args, dict):
user_callback_output = fn(*maybe_progress, **user_callback_args)
elif isinstance(user_callback_args, (list, tuple)):
user_callback_output = fn(*maybe_progress, *user_callback_args)
else:
user_callback_output = fn(*maybe_progress, user_callback_args)
except PreventUpdate:
errored = True
cache.set(result_key, {"_dash_no_update": "_dash_no_update"})
except Exception as err: # pylint: disable=broad-except
errored = True
cache.set(
result_key,
{
"background_callback_error": {
"msg": str(err),
"tb": traceback.format_exc(),
}
},
)
if not errored:
cache.set(result_key, user_callback_output)
async def async_run():
c = AttributeDict(**context)
c.ignore_register_page = False
c.updated_props = ProxySetProps(_set_props)
context_value.set(c)
errored = False
try:
if isinstance(user_callback_args, dict):
user_callback_output = await fn(
*maybe_progress, **user_callback_args
)
elif isinstance(user_callback_args, (list, tuple)):
user_callback_output = await fn(
*maybe_progress, *user_callback_args
)
else:
user_callback_output = await fn(*maybe_progress, user_callback_args)
except PreventUpdate:
errored = True
cache.set(result_key, {"_dash_no_update": "_dash_no_update"})
except Exception as err: # pylint: disable=broad-except
errored = True
cache.set(
result_key,
{
"background_callback_error": {
"msg": str(err),
"tb": traceback.format_exc(),
}
},
)
if asyncio.iscoroutine(user_callback_output):
user_callback_output = await user_callback_output
if not errored:
cache.set(result_key, user_callback_output)
if asyncio.iscoroutinefunction(fn):
func = partial(ctx.run, async_run)
asyncio.run(func())
else:
ctx.run(run)
return job_fn
class DiskcacheLongCallbackManager(DiskcacheManager):
"""Deprecated: use `from dash import DiskcacheManager` instead."""
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,287 @@
import collections
def get_named_tuple(name, dict):
return collections.namedtuple(name, dict.keys())(*dict.values())
Align = get_named_tuple(
"align",
{"default": "", "left": "<", "right": ">", "center": "^", "right_sign": "="},
)
Group = get_named_tuple("group", {"no": "", "yes": ","})
Padding = get_named_tuple("padding", {"no": "", "yes": "0"})
Prefix = get_named_tuple(
"prefix",
{
"yocto": 10**-24,
"zepto": 10**-21,
"atto": 10**-18,
"femto": 10**-15,
"pico": 10**-12,
"nano": 10**-9,
"micro": 10**-6,
"milli": 10**-3,
"none": None,
"kilo": 10**3,
"mega": 10**6,
"giga": 10**9,
"tera": 10**12,
"peta": 10**15,
"exa": 10**18,
"zetta": 10**21,
"yotta": 10**24,
},
)
Scheme = get_named_tuple(
"scheme",
{
"default": "",
"decimal": "r",
"decimal_integer": "d",
"decimal_or_exponent": "g",
"decimal_si_prefix": "s",
"exponent": "e",
"fixed": "f",
"percentage": "%",
"percentage_rounded": "p",
"binary": "b",
"octal": "o",
"lower_case_hex": "x",
"upper_case_hex": "X",
"unicode": "c",
},
)
Sign = get_named_tuple(
"sign",
{"default": "", "negative": "-", "positive": "+", "parantheses": "(", "space": " "},
)
Symbol = get_named_tuple(
"symbol", {"no": "", "yes": "$", "binary": "#b", "octal": "#o", "hex": "#x"}
)
Trim = get_named_tuple("trim", {"no": "", "yes": "~"})
class Format:
def __init__(self, **kwargs):
self._locale = {}
self._nully = ""
self._prefix = Prefix.none
self._specifier = {
"align": Align.default,
"fill": "",
"group": Group.no,
"width": "",
"padding": Padding.no,
"precision": "",
"sign": Sign.default,
"symbol": Symbol.no,
"trim": Trim.no,
"type": Scheme.default,
}
valid_methods = [
m for m in dir(self.__class__) if m[0] != "_" and m != "to_plotly_json"
]
for kw, val in kwargs.items():
if kw not in valid_methods:
raise TypeError(
"{0} is not a format method. Expected one of".format(kw),
str(list(valid_methods)),
)
getattr(self, kw)(val)
def _validate_char(self, value):
self._validate_string(value)
if len(value) != 1:
raise ValueError("expected value to a string of length one")
def _validate_non_negative_integer_or_none(self, value):
if value is None:
return
if not isinstance(value, int):
raise TypeError("expected value to be an integer")
if value < 0:
raise ValueError("expected value to be non-negative", str(value))
def _validate_named(self, value, named_values):
if value not in named_values:
raise TypeError("expected value to be one of", str(list(named_values)))
def _validate_string(self, value):
if not isinstance(value, (str, "".__class__)):
raise TypeError("expected value to be a string")
# Specifier
def align(self, value):
self._validate_named(value, Align)
self._specifier["align"] = value
return self
def fill(self, value):
self._validate_char(value)
self._specifier["fill"] = value
return self
def group(self, value):
if isinstance(value, bool):
value = Group.yes if value else Group.no
self._validate_named(value, Group)
self._specifier["group"] = value
return self
def padding(self, value):
if isinstance(value, bool):
value = Padding.yes if value else Padding.no
self._validate_named(value, Padding)
self._specifier["padding"] = value
return self
def padding_width(self, value):
self._validate_non_negative_integer_or_none(value)
self._specifier["width"] = value if value is not None else ""
return self
def precision(self, value):
self._validate_non_negative_integer_or_none(value)
self._specifier["precision"] = ".{0}".format(value) if value is not None else ""
return self
def scheme(self, value):
self._validate_named(value, Scheme)
self._specifier["type"] = value
return self
def sign(self, value):
self._validate_named(value, Sign)
self._specifier["sign"] = value
return self
def symbol(self, value):
self._validate_named(value, Symbol)
self._specifier["symbol"] = value
return self
def trim(self, value):
if isinstance(value, bool):
value = Trim.yes if value else Trim.no
self._validate_named(value, Trim)
self._specifier["trim"] = value
return self
# Locale
def symbol_prefix(self, value):
self._validate_string(value)
if "symbol" not in self._locale:
self._locale["symbol"] = [value, ""]
else:
self._locale["symbol"][0] = value
return self
def symbol_suffix(self, value):
self._validate_string(value)
if "symbol" not in self._locale:
self._locale["symbol"] = ["", value]
else:
self._locale["symbol"][1] = value
return self
def decimal_delimiter(self, value):
self._validate_char(value)
self._locale["decimal"] = value
return self
def group_delimiter(self, value):
self._validate_char(value)
self._locale["group"] = value
return self
def groups(self, groups):
groups = (
groups
if isinstance(groups, list)
else [groups]
if isinstance(groups, int)
else None
)
if not isinstance(groups, list):
raise TypeError("expected groups to be an integer or a list of integers")
if len(groups) == 0:
raise ValueError(
"expected groups to be an integer or a list of " "one or more integers"
)
for group in groups:
if not isinstance(group, int):
raise TypeError("expected entry to be an integer")
if group <= 0:
raise ValueError("expected entry to be a non-negative integer")
self._locale["grouping"] = groups
return self
# Nully
def nully(self, value):
self._nully = value
return self
# Prefix
def si_prefix(self, value):
self._validate_named(value, Prefix)
self._prefix = value
return self
def to_plotly_json(self):
f = {}
f["locale"] = self._locale.copy()
f["nully"] = self._nully
f["prefix"] = self._prefix
aligned = self._specifier["align"] != Align.default
f["specifier"] = "{}{}{}{}{}{}{}{}{}{}".format(
self._specifier["fill"] if aligned else "",
self._specifier["align"],
self._specifier["sign"],
self._specifier["symbol"],
self._specifier["padding"],
self._specifier["width"],
self._specifier["group"],
self._specifier["precision"],
self._specifier["trim"],
self._specifier["type"],
)
return f
@@ -0,0 +1,19 @@
from .Format import Format, Group, Scheme, Sign, Symbol
def money(decimals, sign=Sign.default):
return Format(
group=Group.yes,
precision=decimals,
scheme=Scheme.fixed,
sign=sign,
symbol=Symbol.yes,
)
def percentage(decimals, rounded=False):
if not isinstance(rounded, bool):
raise TypeError("expected rounded to be a boolean")
rounded = Scheme.percentage_rounded if rounded else Scheme.percentage
return Format(scheme=rounded, precision=decimals)
@@ -0,0 +1,97 @@
# type: ignore
import os as _os
import sys as _sys
import json
import dash as _dash
if not hasattr(_dash, "__plotly_dash") and not hasattr(_dash, "development"):
print(
"Dash was not successfully imported. "
"Make sure you don't have a file "
'named \n"dash.py" in your current directory.',
file=_sys.stderr,
)
_sys.exit(1)
from ._imports_ import * # noqa: E402, F401, F403
from ._imports_ import __all__ as _components
from . import Format # noqa: F401, E402
from . import FormatTemplate # noqa: F401, E402
__all__ = _components + ["Format", "FormatTemplate"]
_basepath = _os.path.dirname(__file__)
_filepath = _os.path.abspath(_os.path.join(_basepath, "package-info.json"))
with open(_filepath) as f:
package = json.load(f)
package_name = package["name"].replace(" ", "_").replace("-", "_")
__version__ = package["version"]
_current_path = _os.path.dirname(_os.path.abspath(__file__))
_this_module = _sys.modules[__name__]
async_resources = ["export", "table", "highlight"]
_js_dist = []
_js_dist.extend(
[
{
"relative_package_path": "dash_table/async-{}.js".format(async_resource),
"external_url": (
"https://unpkg.com/dash-table@{}" "/dash_table/async-{}.js"
).format(__version__, async_resource),
"namespace": "dash",
"async": True,
}
for async_resource in async_resources
]
)
_js_dist.extend(
[
{
"relative_package_path": "dash_table/async-{}.js.map".format(
async_resource
),
"external_url": (
"https://unpkg.com/dash-table@{}" "/dash_table/async-{}.js.map"
).format(__version__, async_resource),
"namespace": "dash",
"dynamic": True,
}
for async_resource in async_resources
]
)
_js_dist.extend(
[
{
"relative_package_path": "dash_table/bundle.js",
"external_url": (
"https://unpkg.com/dash-table@{}/dash_table/bundle.js"
).format(__version__),
"namespace": "dash",
},
{
"relative_package_path": "dash_table/bundle.js.map",
"external_url": (
"https://unpkg.com/dash-table@{}/dash_table/bundle.js.map"
).format(__version__),
"namespace": "dash",
"dynamic": True,
},
]
)
_css_dist = []
for _component in __all__:
setattr(locals()[_component], "_js_dist", _js_dist)
setattr(locals()[_component], "_css_dist", _css_dist)
@@ -0,0 +1,3 @@
from .DataTable import DataTable
__all__ = ["DataTable"]
File diff suppressed because one or more lines are too long
@@ -0,0 +1,3 @@
/*! cpexcel.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*! cputils.js (C) 2013-present SheetJS -- http://sheetjs.com */
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/react-select
*/
/*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
<!doctype>
<html>
<head>
<title>dash-table</title>
</head>
<body>
<div id='root'></div>
<script src='https://unpkg.com/react@16.14.0/umd/react.development.js'></script>
<script src='https://unpkg.com/react-dom@16.14.0/umd/react-dom.development.js'></script>
<script src="./demo.js"></script>
</body>
</html>
File diff suppressed because one or more lines are too long
@@ -0,0 +1,124 @@
{
"name": "dash-table",
"version": "6.0.4",
"description": "Dash table",
"repository": {
"type": "git",
"url": "git@github.com:plotly/dash.git"
},
"bugs": {
"url": "https://github.com/plotly/dash/issues"
},
"homepage": "https://github.com/plotly/dash",
"main": "dash_table/bundle.js",
"scripts": {
"preprivate::test.server": "run-s private::wait_dash*",
"private::build": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack --bail",
"private::build:js": "run-s \"private::build -- --mode production\"",
"private::build:js-test": "run-s \"private::build -- --mode development --config webpack.test.config.js\"",
"private::build:js-test-watch": "run-s \"private::build -- --mode development --config webpack.test.config.js --watch\"",
"private::build:backends": "dash-generate-components src/dash-table/dash/DataTable.js dash_table -p package-info.json && cp dash_table_base/** dash_table/ && dash-generate-components src/dash-table/dash/DataTable.js dash_table -p package-info.json -k DataTable --r-prefix 'dash' --r-suggests 'dash' --jl-prefix 'dash' && black dash_table",
"private::format.ts": "npm run private::lint.ts -- --fix",
"private::format.prettier": "prettier --config .prettierrc --write \"{src,tests,demo}/**/*.{js,ts,tsx}\"",
"private::format.black": "black dash_table_base tests",
"private::lint.ts": "eslint ./src ./tests",
"private::lint.flake": "flake8 dash_table_base tests",
"private::lint.black": "black --check dash_table_base tests",
"private::lint.prettier": "prettier --config .prettierrc \"{src,tests,demo}/**/*.{js,ts,tsx}\" --list-different",
"private::test.python": "python -m unittest tests/unit/format_test.py",
"private::test.unit": "karma start karma.conf.js --single-run",
"build.watch": "webpack serve --disable-host-check --content-base dash_table --mode development --config webpack.dev.config.js",
"build": "run-s private::build:js private::build:backends",
"postbuild": "es-check es2015 dash_table/bundle.js dash_table/async-*.js",
"format": "run-s private::format.*",
"lint": "run-s private::lint.*",
"test.server": "pytest --nopercyfinalize tests/selenium",
"test.unit": "run-s private::test.python private::test.unit",
"test.visual": "npm install --package-lock-only=false --no-save @percy/storybook@^3.3.1 @storybook/builder-webpack5@^6.5.13 @storybook/cli@^6.5.13 @storybook/manager-webpack5@^6.5.16 @storybook/react@^6.5.13 @storybook/semver@^7.3.2 && build-storybook && percy-storybook --widths=1280",
"test.visual-local": "npm install --package-lock-only=false --no-save @percy/storybook@^3.3.1 @storybook/builder-webpack5@^6.5.13 @storybook/cli@^6.5.13 @storybook/manager-webpack5@^6.5.16 @storybook/react@^6.5.13 @storybook/semver@^7.3.2 && build-storybook"
},
"author": "Chris Parmer <chris@plotly.com>",
"maintainer": "Alex Johnson <alex@plotly.com>",
"license": "MIT",
"devDependencies": {
"@babel/cli": "^7.28.0",
"@babel/core": "^7.28.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-regenerator": "^7.28.1",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.28.0",
"@babel/preset-react": "^7.27.1",
"@fortawesome/fontawesome-svg-core": "1.2.36",
"@fortawesome/free-regular-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.2.2",
"@plotly/dash-component-plugins": "^1.2.3",
"@plotly/webpack-dash-dynamic-import": "^1.3.0",
"@types/chai": "^4.3.5",
"@types/d3-format": "^3.0.1",
"@types/mocha": "^10.0.1",
"@types/papaparse": "^5.3.7",
"@types/ramda": "0.30.2",
"@types/react": "^16.14.8",
"@types/react-dom": "^16.9.13",
"@types/react-select": "^4.0.16",
"@typescript-eslint/eslint-plugin": "^5.59.7",
"@typescript-eslint/parser": "^5.59.7",
"babel-loader": "^9.2.1",
"chai": "^4.3.7",
"css-loader": "^6.8.1",
"css.escape": "^1.5.1",
"d3-format": "^3.1.0",
"es-check": "^7.1.1",
"eslint": "^8.41.0",
"eslint-config-prettier": "^8.8.0",
"fast-isnumeric": "^1.1.4",
"file-loader": "^6.2.0",
"highlight.js": "^11.8.0",
"karma": "^6.4.2",
"karma-chrome-launcher": "^3.2.0",
"karma-mocha": "^2.0.1",
"karma-typescript": "^5.5.4",
"karma-webpack": "^5.0.0",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"mocha": "^10.2.0",
"npm-run-all": "^4.1.5",
"papaparse": "^5.4.1",
"prettier": "^2.8.8",
"ramda": "^0.30.1",
"raw-loader": "^4.0.2",
"react": "^16.14.0",
"react-docgen": "^5.4.3",
"react-dom": "^16.14.0",
"react-select": "^1.3.0",
"regenerator-runtime": "^0.13.11",
"remarkable": "^2.0.1",
"sheetclip": "^0.3.0",
"style-loader": "^3.3.3",
"ts-loader": "^9.5.2",
"typescript": "^5.8.3",
"webpack": "^5.101.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "5.2.2",
"webpack-preprocessor": "^0.1.12",
"xlsx": "^0.17.5",
"rimraf": "^5.0.5"
},
"files": [
"/dash_table/async-*{.js,.map}",
"/dash_table/bundle*{.js,.map}"
],
"peerDependencies": {
"prop-types": "^15.7.2",
"react": ">=16",
"react-dom": ">=16"
},
"engines": {
"node": ">=12.0.0",
"npm": ">=6.1.0"
},
"browserslist": [
"last 9 years and not dead"
]
}
@@ -0,0 +1,179 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Checklist(Component):
"""A Checklist component.
Checklist is a component that encapsulates several checkboxes.
The values and labels of the checklist are specified in the `options`
property and the checked items are specified with the `value` property.
Each checkbox is rendered as an input with a surrounding label.
Keyword arguments:
- options (list of dicts; optional):
An array of options.
`options` is a list of string | number | booleans | dict | list of
dicts with keys:
- label (a list of or a singular dash component, string or number; required):
The option's label.
- value (string | number | boolean; required):
The value of the option. This value corresponds to the items
specified in the `value` property.
- disabled (boolean; optional):
If True, this option is disabled and cannot be selected.
- title (string; optional):
The HTML 'title' attribute for the option. Allows for
information on hover. For more information on this attribute,
see
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title.
- value (list of string | number | booleans; optional):
The currently selected value.
- inline (boolean; default False):
Indicates whether the options labels should be displayed inline
(True=horizontal) or in a block (False=vertical).
- className (string; optional):
The class of the container (div).
- inputStyle (dict; optional):
The style of the <input> checkbox element.
- inputClassName (string; default ''):
The class of the <input> checkbox element.
- labelStyle (dict; optional):
The style of the <label> that wraps the checkbox input and the
option's label.
- labelClassName (string; default ''):
The class of the <label> that wraps the checkbox input and the
option's label.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `value` that
the user has changed while using the app will keep that change, as
long as the new `value` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persisted_props (list of a value equal to: 'value's; default ['value']):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `value` is allowed this prop
can normally be ignored.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit."""
_children_props = ["options[].label"]
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Checklist"
Options = TypedDict(
"Options",
{
"label": ComponentType,
"value": typing.Union[str, NumberType, bool],
"disabled": NotRequired[bool],
"title": NotRequired[str],
},
)
def __init__(
self,
options: typing.Optional[
typing.Union[
typing.Sequence[typing.Union[str, NumberType, bool]],
dict,
typing.Sequence["Options"],
]
] = None,
value: typing.Optional[
typing.Sequence[typing.Union[str, NumberType, bool]]
] = None,
inline: typing.Optional[bool] = None,
className: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
inputStyle: typing.Optional[dict] = None,
inputClassName: typing.Optional[str] = None,
labelStyle: typing.Optional[dict] = None,
labelClassName: typing.Optional[str] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["value"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"options",
"value",
"inline",
"className",
"style",
"inputStyle",
"inputClassName",
"labelStyle",
"labelClassName",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"options",
"value",
"inline",
"className",
"style",
"inputStyle",
"inputClassName",
"labelStyle",
"labelClassName",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Checklist, self).__init__(**args)
setattr(Checklist, "__init__", _explicitize_args(Checklist.__init__))
@@ -0,0 +1,99 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Clipboard(Component):
"""A Clipboard component.
The Clipboard component copies text to the clipboard
Keyword arguments:
- id (string; optional):
The ID used to identify this component.
- className (string; optional):
The class name of the icon element.
- content (string; optional):
The text to be copied to the clipboard if the `target_id` is None.
- html_content (string; optional):
The clipboard html text be copied to the clipboard if the
`target_id` is None.
- n_clicks (number; default 0):
The number of times copy button was clicked.
- target_id (string | dict; optional):
The id of target component containing text to copy to the
clipboard. The inner text of the `children` prop will be copied to
the clipboard. If none, then the text from the `value` prop will
be copied.
- title (string; optional):
The text shown as a tooltip when hovering over the copy icon."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Clipboard"
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
target_id: typing.Optional[typing.Union[str, dict]] = None,
content: typing.Optional[str] = None,
n_clicks: typing.Optional[NumberType] = None,
html_content: typing.Optional[str] = None,
title: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
className: typing.Optional[str] = None,
**kwargs
):
self._prop_names = [
"id",
"className",
"content",
"html_content",
"n_clicks",
"style",
"target_id",
"title",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"id",
"className",
"content",
"html_content",
"n_clicks",
"style",
"target_id",
"title",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Clipboard, self).__init__(**args)
setattr(Clipboard, "__init__", _explicitize_args(Clipboard.__init__))
@@ -0,0 +1,97 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class ConfirmDialog(Component):
"""A ConfirmDialog component.
ConfirmDialog is used to display the browser's native "confirm" modal,
with an optional message and two buttons ("OK" and "Cancel").
This ConfirmDialog can be used in conjunction with buttons when the user
is performing an action that should require an extra step of verification.
Keyword arguments:
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- cancel_n_clicks (number; default 0):
Number of times the popup was canceled.
- cancel_n_clicks_timestamp (number; default -1):
Last time the cancel button was clicked.
- displayed (boolean; optional):
Set to True to send the ConfirmDialog.
- message (string; optional):
Message to show in the popup.
- submit_n_clicks (number; default 0):
Number of times the submit button was clicked.
- submit_n_clicks_timestamp (number; default -1):
Last time the submit button was clicked."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "ConfirmDialog"
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
message: typing.Optional[str] = None,
submit_n_clicks: typing.Optional[NumberType] = None,
submit_n_clicks_timestamp: typing.Optional[NumberType] = None,
cancel_n_clicks: typing.Optional[NumberType] = None,
cancel_n_clicks_timestamp: typing.Optional[NumberType] = None,
displayed: typing.Optional[bool] = None,
**kwargs
):
self._prop_names = [
"id",
"cancel_n_clicks",
"cancel_n_clicks_timestamp",
"displayed",
"message",
"submit_n_clicks",
"submit_n_clicks_timestamp",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"id",
"cancel_n_clicks",
"cancel_n_clicks_timestamp",
"displayed",
"message",
"submit_n_clicks",
"submit_n_clicks_timestamp",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(ConfirmDialog, self).__init__(**args)
setattr(ConfirmDialog, "__init__", _explicitize_args(ConfirmDialog.__init__))
@@ -0,0 +1,111 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class ConfirmDialogProvider(Component):
"""A ConfirmDialogProvider component.
A wrapper component that will display a confirmation dialog
when its child component has been clicked on.
For example:
```
dcc.ConfirmDialogProvider(
html.Button('click me', id='btn'),
message='Danger - Are you sure you want to continue.'
id='confirm')
```
Keyword arguments:
- children (boolean | number | string | dict | list; optional):
The children to hijack clicks from and display the popup.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- cancel_n_clicks (number; default 0):
Number of times the popup was canceled.
- cancel_n_clicks_timestamp (number; default -1):
Last time the cancel button was clicked.
- displayed (boolean; optional):
Is the modal currently displayed.
- message (string; optional):
Message to show in the popup.
- submit_n_clicks (number; default 0):
Number of times the submit was clicked.
- submit_n_clicks_timestamp (number; default -1):
Last time the submit button was clicked."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "ConfirmDialogProvider"
def __init__(
self,
children: typing.Optional[ComponentType] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
message: typing.Optional[str] = None,
submit_n_clicks: typing.Optional[NumberType] = None,
submit_n_clicks_timestamp: typing.Optional[NumberType] = None,
cancel_n_clicks: typing.Optional[NumberType] = None,
cancel_n_clicks_timestamp: typing.Optional[NumberType] = None,
displayed: typing.Optional[bool] = None,
**kwargs
):
self._prop_names = [
"children",
"id",
"cancel_n_clicks",
"cancel_n_clicks_timestamp",
"displayed",
"message",
"submit_n_clicks",
"submit_n_clicks_timestamp",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"children",
"id",
"cancel_n_clicks",
"cancel_n_clicks_timestamp",
"displayed",
"message",
"submit_n_clicks",
"submit_n_clicks_timestamp",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args if k != "children"}
super(ConfirmDialogProvider, self).__init__(children=children, **args)
setattr(
ConfirmDialogProvider, "__init__", _explicitize_args(ConfirmDialogProvider.__init__)
)
@@ -0,0 +1,302 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
import datetime
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class DatePickerRange(Component):
"""A DatePickerRange component.
DatePickerRange is a tailor made component designed for selecting
timespan across multiple days off of a calendar.
The DatePicker integrates well with the Python datetime module with the
startDate and endDate being returned in a string format suitable for
creating datetime objects.
This component is based off of Airbnb's react-dates react component
which can be found here: https://github.com/airbnb/react-dates
Keyword arguments:
- start_date (string; optional):
Specifies the starting date for the component. Accepts
datetime.datetime objects or strings in the format 'YYYY-MM-DD'.
- end_date (string; optional):
Specifies the ending date for the component. Accepts
datetime.datetime objects or strings in the format 'YYYY-MM-DD'.
- min_date_allowed (string; optional):
Specifies the lowest selectable date for the component. Accepts
datetime.datetime objects or strings in the format 'YYYY-MM-DD'.
- max_date_allowed (string; optional):
Specifies the highest selectable date for the component. Accepts
datetime.datetime objects or strings in the format 'YYYY-MM-DD'.
- disabled_days (list of strings; optional):
Specifies additional days between min_date_allowed and
max_date_allowed that should be disabled. Accepted
datetime.datetime objects or strings in the format 'YYYY-MM-DD'.
- minimum_nights (number; optional):
Specifies a minimum number of nights that must be selected between
the startDate and the endDate.
- updatemode (a value equal to: 'singledate', 'bothdates'; default 'singledate'):
Determines when the component should update its value. If
`bothdates`, then the DatePicker will only trigger its value when
the user has finished picking both dates. If `singledate`, then
the DatePicker will update its value as one date is picked.
- start_date_placeholder_text (string; optional):
Text that will be displayed in the first input box of the date
picker when no date is selected. Default value is 'Start Date'.
- end_date_placeholder_text (string; optional):
Text that will be displayed in the second input box of the date
picker when no date is selected. Default value is 'End Date'.
- initial_visible_month (string; optional):
Specifies the month that is initially presented when the user
opens the calendar. Accepts datetime.datetime objects or strings
in the format 'YYYY-MM-DD'.
- clearable (boolean; default False):
Whether or not the dropdown is \"clearable\", that is, whether or
not a small \"x\" appears on the right of the dropdown that
removes the selected value.
- reopen_calendar_on_clear (boolean; default False):
If True, the calendar will automatically open when cleared.
- display_format (string; optional):
Specifies the format that the selected dates will be displayed
valid formats are variations of \"MM YY DD\". For example: \"MM YY
DD\" renders as '05 10 97' for May 10th 1997 \"MMMM, YY\" renders
as 'May, 1997' for May 10th 1997 \"M, D, YYYY\" renders as '07,
10, 1997' for September 10th 1997 \"MMMM\" renders as 'May' for
May 10 1997.
- month_format (string; optional):
Specifies the format that the month will be displayed in the
calendar, valid formats are variations of \"MM YY\". For example:
\"MM YY\" renders as '05 97' for May 1997 \"MMMM, YYYY\" renders
as 'May, 1997' for May 1997 \"MMM, YY\" renders as 'Sep, 97' for
September 1997.
- first_day_of_week (a value equal to: 0, 1, 2, 3, 4, 5, 6; default 0):
Specifies what day is the first day of the week, values must be
from [0, ..., 6] with 0 denoting Sunday and 6 denoting Saturday.
- show_outside_days (boolean; optional):
If True the calendar will display days that rollover into the next
month.
- stay_open_on_select (boolean; default False):
If True the calendar will not close when the user has selected a
value and will wait until the user clicks off the calendar.
- calendar_orientation (a value equal to: 'vertical', 'horizontal'; default 'horizontal'):
Orientation of calendar, either vertical or horizontal. Valid
options are 'vertical' or 'horizontal'.
- number_of_months_shown (number; default 1):
Number of calendar months that are shown when calendar is opened.
- with_portal (boolean; default False):
If True, calendar will open in a screen overlay portal, not
supported on vertical calendar.
- with_full_screen_portal (boolean; default False):
If True, calendar will open in a full screen overlay portal, will
take precedent over 'withPortal' if both are set to True, not
supported on vertical calendar.
- day_size (number; default 39):
Size of rendered calendar days, higher number means bigger day
size and larger calendar overall.
- is_RTL (boolean; default False):
Determines whether the calendar and days operate from left to
right or from right to left.
- disabled (boolean; default False):
If True, no dates can be selected.
- start_date_id (string; optional):
The HTML element ID of the start date input field. Not used by
Dash, only by CSS.
- end_date_id (string; optional):
The HTML element ID of the end date input field. Not used by Dash,
only by CSS.
- className (string; optional):
Appends a CSS class to the wrapper div component.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, any
`persisted_props` that the user has changed while using the app
will keep those changes, as long as the new prop value also
matches what was given originally. Used in conjunction with
`persistence_type` and `persisted_props`.
- persisted_props (list of a value equal to: 'start_date', 'end_date's; default ['start_date', 'end_date']):
Properties whose user interactions will persist after refreshing
the component or the page.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "DatePickerRange"
def __init__(
self,
start_date: typing.Optional[typing.Union[str, datetime.datetime]] = None,
end_date: typing.Optional[typing.Union[str, datetime.datetime]] = None,
min_date_allowed: typing.Optional[typing.Union[str, datetime.datetime]] = None,
max_date_allowed: typing.Optional[typing.Union[str, datetime.datetime]] = None,
disabled_days: typing.Optional[
typing.Sequence[typing.Union[str, datetime.datetime]]
] = None,
minimum_nights: typing.Optional[NumberType] = None,
updatemode: typing.Optional[Literal["singledate", "bothdates"]] = None,
start_date_placeholder_text: typing.Optional[str] = None,
end_date_placeholder_text: typing.Optional[str] = None,
initial_visible_month: typing.Optional[str] = None,
clearable: typing.Optional[bool] = None,
reopen_calendar_on_clear: typing.Optional[bool] = None,
display_format: typing.Optional[str] = None,
month_format: typing.Optional[str] = None,
first_day_of_week: typing.Optional[Literal[0, 1, 2, 3, 4, 5, 6]] = None,
show_outside_days: typing.Optional[bool] = None,
stay_open_on_select: typing.Optional[bool] = None,
calendar_orientation: typing.Optional[Literal["vertical", "horizontal"]] = None,
number_of_months_shown: typing.Optional[NumberType] = None,
with_portal: typing.Optional[bool] = None,
with_full_screen_portal: typing.Optional[bool] = None,
day_size: typing.Optional[NumberType] = None,
is_RTL: typing.Optional[bool] = None,
disabled: typing.Optional[bool] = None,
start_date_id: typing.Optional[str] = None,
end_date_id: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
className: typing.Optional[str] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[
typing.Sequence[Literal["start_date", "end_date"]]
] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"start_date",
"end_date",
"min_date_allowed",
"max_date_allowed",
"disabled_days",
"minimum_nights",
"updatemode",
"start_date_placeholder_text",
"end_date_placeholder_text",
"initial_visible_month",
"clearable",
"reopen_calendar_on_clear",
"display_format",
"month_format",
"first_day_of_week",
"show_outside_days",
"stay_open_on_select",
"calendar_orientation",
"number_of_months_shown",
"with_portal",
"with_full_screen_portal",
"day_size",
"is_RTL",
"disabled",
"start_date_id",
"end_date_id",
"style",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"start_date",
"end_date",
"min_date_allowed",
"max_date_allowed",
"disabled_days",
"minimum_nights",
"updatemode",
"start_date_placeholder_text",
"end_date_placeholder_text",
"initial_visible_month",
"clearable",
"reopen_calendar_on_clear",
"display_format",
"month_format",
"first_day_of_week",
"show_outside_days",
"stay_open_on_select",
"calendar_orientation",
"number_of_months_shown",
"with_portal",
"with_full_screen_portal",
"day_size",
"is_RTL",
"disabled",
"start_date_id",
"end_date_id",
"style",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(DatePickerRange, self).__init__(**args)
setattr(DatePickerRange, "__init__", _explicitize_args(DatePickerRange.__init__))
@@ -0,0 +1,258 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
import datetime
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class DatePickerSingle(Component):
"""A DatePickerSingle component.
DatePickerSingle is a tailor made component designed for selecting
a single day off of a calendar.
The DatePicker integrates well with the Python datetime module with the
startDate and endDate being returned in a string format suitable for
creating datetime objects.
This component is based off of Airbnb's react-dates react component
which can be found here: https://github.com/airbnb/react-dates
Keyword arguments:
- date (string; optional):
Specifies the starting date for the component, best practice is to
pass value via datetime object.
- min_date_allowed (string; optional):
Specifies the lowest selectable date for the component. Accepts
datetime.datetime objects or strings in the format 'YYYY-MM-DD'.
- max_date_allowed (string; optional):
Specifies the highest selectable date for the component. Accepts
datetime.datetime objects or strings in the format 'YYYY-MM-DD'.
- disabled_days (list of strings; optional):
Specifies additional days between min_date_allowed and
max_date_allowed that should be disabled. Accepted
datetime.datetime objects or strings in the format 'YYYY-MM-DD'.
- placeholder (string; optional):
Text that will be displayed in the input box of the date picker
when no date is selected. Default value is 'Start Date'.
- initial_visible_month (string; optional):
Specifies the month that is initially presented when the user
opens the calendar. Accepts datetime.datetime objects or strings
in the format 'YYYY-MM-DD'.
- clearable (boolean; default False):
Whether or not the dropdown is \"clearable\", that is, whether or
not a small \"x\" appears on the right of the dropdown that
removes the selected value.
- reopen_calendar_on_clear (boolean; default False):
If True, the calendar will automatically open when cleared.
- display_format (string; optional):
Specifies the format that the selected dates will be displayed
valid formats are variations of \"MM YY DD\". For example: \"MM YY
DD\" renders as '05 10 97' for May 10th 1997 \"MMMM, YY\" renders
as 'May, 1997' for May 10th 1997 \"M, D, YYYY\" renders as '07,
10, 1997' for September 10th 1997 \"MMMM\" renders as 'May' for
May 10 1997.
- month_format (string; optional):
Specifies the format that the month will be displayed in the
calendar, valid formats are variations of \"MM YY\". For example:
\"MM YY\" renders as '05 97' for May 1997 \"MMMM, YYYY\" renders
as 'May, 1997' for May 1997 \"MMM, YY\" renders as 'Sep, 97' for
September 1997.
- first_day_of_week (a value equal to: 0, 1, 2, 3, 4, 5, 6; default 0):
Specifies what day is the first day of the week, values must be
from [0, ..., 6] with 0 denoting Sunday and 6 denoting Saturday.
- show_outside_days (boolean; default True):
If True the calendar will display days that rollover into the next
month.
- stay_open_on_select (boolean; default False):
If True the calendar will not close when the user has selected a
value and will wait until the user clicks off the calendar.
- calendar_orientation (a value equal to: 'vertical', 'horizontal'; default 'horizontal'):
Orientation of calendar, either vertical or horizontal. Valid
options are 'vertical' or 'horizontal'.
- number_of_months_shown (number; default 1):
Number of calendar months that are shown when calendar is opened.
- with_portal (boolean; default False):
If True, calendar will open in a screen overlay portal, not
supported on vertical calendar.
- with_full_screen_portal (boolean; default False):
If True, calendar will open in a full screen overlay portal, will
take precedent over 'withPortal' if both are set to True, not
supported on vertical calendar.
- day_size (number; default 39):
Size of rendered calendar days, higher number means bigger day
size and larger calendar overall.
- is_RTL (boolean; default False):
Determines whether the calendar and days operate from left to
right or from right to left.
- disabled (boolean; default False):
If True, no dates can be selected.
- className (string; optional):
Appends a CSS class to the wrapper div component.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `date` that
the user has changed while using the app will keep that change, as
long as the new `date` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persisted_props (list of a value equal to: 'date's; default ['date']):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `date` is allowed this prop
can normally be ignored.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "DatePickerSingle"
def __init__(
self,
date: typing.Optional[typing.Union[str, datetime.datetime]] = None,
min_date_allowed: typing.Optional[typing.Union[str, datetime.datetime]] = None,
max_date_allowed: typing.Optional[typing.Union[str, datetime.datetime]] = None,
disabled_days: typing.Optional[
typing.Sequence[typing.Union[str, datetime.datetime]]
] = None,
placeholder: typing.Optional[str] = None,
initial_visible_month: typing.Optional[
typing.Union[str, datetime.datetime]
] = None,
clearable: typing.Optional[bool] = None,
reopen_calendar_on_clear: typing.Optional[bool] = None,
display_format: typing.Optional[str] = None,
month_format: typing.Optional[str] = None,
first_day_of_week: typing.Optional[Literal[0, 1, 2, 3, 4, 5, 6]] = None,
show_outside_days: typing.Optional[bool] = None,
stay_open_on_select: typing.Optional[bool] = None,
calendar_orientation: typing.Optional[Literal["vertical", "horizontal"]] = None,
number_of_months_shown: typing.Optional[NumberType] = None,
with_portal: typing.Optional[bool] = None,
with_full_screen_portal: typing.Optional[bool] = None,
day_size: typing.Optional[NumberType] = None,
is_RTL: typing.Optional[bool] = None,
disabled: typing.Optional[bool] = None,
style: typing.Optional[typing.Any] = None,
className: typing.Optional[str] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["date"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"date",
"min_date_allowed",
"max_date_allowed",
"disabled_days",
"placeholder",
"initial_visible_month",
"clearable",
"reopen_calendar_on_clear",
"display_format",
"month_format",
"first_day_of_week",
"show_outside_days",
"stay_open_on_select",
"calendar_orientation",
"number_of_months_shown",
"with_portal",
"with_full_screen_portal",
"day_size",
"is_RTL",
"disabled",
"style",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"date",
"min_date_allowed",
"max_date_allowed",
"disabled_days",
"placeholder",
"initial_visible_month",
"clearable",
"reopen_calendar_on_clear",
"display_format",
"month_format",
"first_day_of_week",
"show_outside_days",
"stay_open_on_select",
"calendar_orientation",
"number_of_months_shown",
"with_portal",
"with_full_screen_portal",
"day_size",
"is_RTL",
"disabled",
"style",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(DatePickerSingle, self).__init__(**args)
setattr(DatePickerSingle, "__init__", _explicitize_args(DatePickerSingle.__init__))
@@ -0,0 +1,90 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Download(Component):
"""A Download component.
The Download component opens a download dialog when the data property changes.
Keyword arguments:
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks.
- base64 (boolean; default False):
Default value for base64, used when not set as part of the data
property.
- data (dict; optional):
On change, a download is invoked.
`data` is a dict with keys:
- filename (string; required):
Suggested filename in the download dialogue.
- content (string; required):
File content.
- base64 (boolean; optional):
Set to True, when data is base64 encoded.
- type (string; optional):
Blob type, usually a MIME-type.
- type (string; default 'text/plain'):
Default value for type, used when not set as part of the data
property."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Download"
Data = TypedDict(
"Data",
{
"filename": str,
"content": str,
"base64": NotRequired[bool],
"type": NotRequired[str],
},
)
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
data: typing.Optional["Data"] = None,
base64: typing.Optional[bool] = None,
type: typing.Optional[str] = None,
**kwargs
):
self._prop_names = ["id", "base64", "data", "type"]
self._valid_wildcard_attributes = []
self.available_properties = ["id", "base64", "data", "type"]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Download, self).__init__(**args)
setattr(Download, "__init__", _explicitize_args(Download.__init__))
@@ -0,0 +1,227 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Dropdown(Component):
"""A Dropdown component.
Dropdown is an interactive dropdown element for selecting one or more
items.
The values and labels of the dropdown items are specified in the `options`
property and the selected item(s) are specified with the `value` property.
Use a dropdown when you have many options (more than 5) or when you are
constrained for space. Otherwise, you can use RadioItems or a Checklist,
which have the benefit of showing the users all of the items at once.
Keyword arguments:
- options (list of dicts; optional):
An array of options {label: [string|number], value:
[string|number]}, an optional disabled field can be used for each
option.
`options` is a list of string | number | booleans | dict | list of
dicts with keys:
- label (a list of or a singular dash component, string or number; required):
The option's label.
- value (string | number | boolean; required):
The value of the option. This value corresponds to the items
specified in the `value` property.
- disabled (boolean; optional):
If True, this option is disabled and cannot be selected.
- title (string; optional):
The HTML 'title' attribute for the option. Allows for
information on hover. For more information on this attribute,
see
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title.
- search (string; optional):
Optional search value for the option, to use if the label is a
component or provide a custom search value different from the
label. If no search value and the label is a component, the
`value` will be used for search.
- value (string | number | boolean | list of string | number | booleans; optional):
The value of the input. If `multi` is False (the default) then
value is just a string that corresponds to the values provided in
the `options` property. If `multi` is True, then multiple values
can be selected at once, and `value` is an array of items with
values corresponding to those in the `options` prop.
- multi (boolean; default False):
If True, the user can select multiple values.
- clearable (boolean; default True):
Whether or not the dropdown is \"clearable\", that is, whether or
not a small \"x\" appears on the right of the dropdown that
removes the selected value.
- searchable (boolean; default True):
Whether to enable the searching feature or not.
- search_value (string; optional):
The value typed in the DropDown for searching.
- placeholder (string; optional):
The grey, default text shown when no option is selected.
- disabled (boolean; default False):
If True, this dropdown is disabled and the selection cannot be
changed.
- closeOnSelect (boolean; default True):
If False, the menu of the dropdown will not close once a value is
selected.
- optionHeight (number; default 35):
height of each option. Can be increased when label lengths would
wrap around.
- maxHeight (number; default 200):
height of the options dropdown.
- className (string; optional):
className of the dropdown element.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `value` that
the user has changed while using the app will keep that change, as
long as the new `value` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persisted_props (list of a value equal to: 'value's; default ['value']):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `value` is allowed this prop
can normally be ignored.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit."""
_children_props = ["options[].label"]
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Dropdown"
Options = TypedDict(
"Options",
{
"label": ComponentType,
"value": typing.Union[str, NumberType, bool],
"disabled": NotRequired[bool],
"title": NotRequired[str],
"search": NotRequired[str],
},
)
def __init__(
self,
options: typing.Optional[
typing.Union[
typing.Sequence[typing.Union[str, NumberType, bool]],
dict,
typing.Sequence["Options"],
]
] = None,
value: typing.Optional[
typing.Union[
str,
NumberType,
bool,
typing.Sequence[typing.Union[str, NumberType, bool]],
]
] = None,
multi: typing.Optional[bool] = None,
clearable: typing.Optional[bool] = None,
searchable: typing.Optional[bool] = None,
search_value: typing.Optional[str] = None,
placeholder: typing.Optional[str] = None,
disabled: typing.Optional[bool] = None,
closeOnSelect: typing.Optional[bool] = None,
optionHeight: typing.Optional[NumberType] = None,
maxHeight: typing.Optional[NumberType] = None,
style: typing.Optional[typing.Any] = None,
className: typing.Optional[str] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["value"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"options",
"value",
"multi",
"clearable",
"searchable",
"search_value",
"placeholder",
"disabled",
"closeOnSelect",
"optionHeight",
"maxHeight",
"style",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"options",
"value",
"multi",
"clearable",
"searchable",
"search_value",
"placeholder",
"disabled",
"closeOnSelect",
"optionHeight",
"maxHeight",
"style",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Dropdown, self).__init__(**args)
setattr(Dropdown, "__init__", _explicitize_args(Dropdown.__init__))
@@ -0,0 +1,173 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Geolocation(Component):
"""A Geolocation component.
The CurrentLocation component gets geolocation of the device from the web browser. See more info here:
https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API
Keyword arguments:
- id (string; optional):
The ID used to identify this component in Dash callbacks.
- high_accuracy (boolean; default False):
If True and if the device is able to provide a more accurate
position, it will do so. Note that this can result in slower
response times or increased power consumption (with a GPS chip on
a mobile device for example). If False (the default value), the
device can save resources by responding more quickly and/or using
less power.
- local_date (string; optional):
The local date and time when the device position was updated.
Format: MM/DD/YYYY, hh:mm:ss p where p is AM or PM.
- maximum_age (number; default 0):
The maximum age in milliseconds of a possible cached position that
is acceptable to return. If set to 0, it means that the device
cannot use a cached position and must attempt to retrieve the real
current position. If set to Infinity the device must return a
cached position regardless of its age. Default: 0.
- position (dict; optional):
The position of the device. `lat`, `lon`, and `accuracy` will
always be returned. The other data will be included when
available, otherwise it will be NaN. `lat` is latitude in
degrees. `lon` is longitude in degrees. `accuracy` is
the accuracy of the lat/lon in meters. * `alt` is
altitude above mean sea level in meters. `alt_accuracy` is
the accuracy of the altitude in meters. `heading` is the
compass heading in degrees. `speed` is the speed in meters
per second.
`position` is a dict with keys:
- lat (number; optional)
- lon (number; optional)
- accuracy (number; optional)
- alt (number; optional)
- alt_accuracy (number; optional)
- heading (number; optional)
- speed (number; optional)
- position_error (dict; optional):
Position error.
`position_error` is a dict with keys:
- code (number; optional)
- message (string; optional)
- show_alert (boolean; default False):
If True, error messages will be displayed as an alert.
- timeout (number; default Infinity):
The maximum length of time (in milliseconds) the device is allowed
to take in order to return a position. The default value is
Infinity, meaning that data will not be return until the position
is available.
- timestamp (number; optional):
The Unix timestamp from when the position was updated.
- update_now (boolean; default False):
Forces a one-time update of the position data. If set to True in
a callback, the browser will update the position data and reset
update_now back to False. This can, for example, be used to
update the position with a button or an interval timer."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Geolocation"
Position = TypedDict(
"Position",
{
"lat": NotRequired[NumberType],
"lon": NotRequired[NumberType],
"accuracy": NotRequired[NumberType],
"alt": NotRequired[NumberType],
"alt_accuracy": NotRequired[NumberType],
"heading": NotRequired[NumberType],
"speed": NotRequired[NumberType],
},
)
PositionError = TypedDict(
"PositionError", {"code": NotRequired[NumberType], "message": NotRequired[str]}
)
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
local_date: typing.Optional[str] = None,
timestamp: typing.Optional[NumberType] = None,
position: typing.Optional["Position"] = None,
position_error: typing.Optional["PositionError"] = None,
show_alert: typing.Optional[bool] = None,
update_now: typing.Optional[bool] = None,
high_accuracy: typing.Optional[bool] = None,
maximum_age: typing.Optional[NumberType] = None,
timeout: typing.Optional[NumberType] = None,
**kwargs
):
self._prop_names = [
"id",
"high_accuracy",
"local_date",
"maximum_age",
"position",
"position_error",
"show_alert",
"timeout",
"timestamp",
"update_now",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"id",
"high_accuracy",
"local_date",
"maximum_age",
"position",
"position_error",
"show_alert",
"timeout",
"timestamp",
"update_now",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Geolocation, self).__init__(**args)
setattr(Geolocation, "__init__", _explicitize_args(Geolocation.__init__))
@@ -0,0 +1,463 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
from plotly.graph_objects import Figure
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Graph(Component):
"""A Graph component.
Graph can be used to render any plotly.js-powered data visualization.
You can define callbacks based on user interaction with Graphs such as
hovering, clicking or selecting
Keyword arguments:
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- animate (boolean; default False):
Beta: If True, animate between updates using plotly.js's `animate`
function.
- animation_options (dict; default { frame: { redraw: False, }, transition: { duration: 750, ease: 'cubic-in-out', },}):
Beta: Object containing animation settings. Only applies if
`animate` is `True`.
- className (string; optional):
className of the parent div.
- clear_on_unhover (boolean; default False):
If True, `clear_on_unhover` will clear the `hoverData` property
when the user \"unhovers\" from a point. If False, then the
`hoverData` property will be equal to the data from the last point
that was hovered over.
- clickAnnotationData (dict; optional):
Data from latest click annotation event. Read-only.
- clickData (dict; optional):
Data from latest click event. Read-only.
- config (dict; optional):
Plotly.js config options. See
https://plotly.com/javascript/configuration-options/ for more
info.
`config` is a dict with keys:
- staticPlot (boolean; optional):
No interactivity, for export or image generation.
- plotlyServerURL (string; optional):
Base URL for a Plotly cloud instance, if `showSendToCloud` is
enabled.
- editable (boolean; optional):
We can edit titles, move annotations, etc - sets all pieces of
`edits` unless a separate `edits` config item overrides
individual parts.
- editSelection (boolean; optional):
Enables moving selections.
- edits (dict; optional):
A set of editable properties.
`edits` is a dict with keys:
- annotationPosition (boolean; optional):
The main anchor of the annotation, which is the text (if
no arrow) or the arrow (which drags the whole thing
leaving the arrow length & direction unchanged).
- annotationTail (boolean; optional):
Just for annotations with arrows, change the length and
direction of the arrow.
- annotationText (boolean; optional)
- axisTitleText (boolean; optional)
- colorbarPosition (boolean; optional)
- colorbarTitleText (boolean; optional)
- legendPosition (boolean; optional)
- legendText (boolean; optional):
Edit the trace name fields from the legend.
- shapePosition (boolean; optional)
- titleText (boolean; optional):
The global `layout.title`.
- autosizable (boolean; optional):
DO autosize once regardless of layout.autosize (use default
width or height values otherwise).
- responsive (boolean; optional):
Whether to change layout size when the window size changes.
- queueLength (number; optional):
Set the length of the undo/redo queue.
- fillFrame (boolean; optional):
If we DO autosize, do we fill the container or the screen?.
- frameMargins (number; optional):
If we DO autosize, set the frame margins in percents of plot
size.
- scrollZoom (boolean; optional):
Mousewheel or two-finger scroll zooms the plot.
- doubleClick (a value equal to: false, 'reset', 'autosize', 'reset+autosize'; optional):
Double click interaction (False, 'reset', 'autosize' or
'reset+autosize').
- doubleClickDelay (number; optional):
Delay for registering a double-click event in ms. The minimum
value is 100 and the maximum value is 1000. By default this is
300.
- showTips (boolean; optional):
New users see some hints about interactivity.
- showAxisDragHandles (boolean; optional):
Enable axis pan/zoom drag handles.
- showAxisRangeEntryBoxes (boolean; optional):
Enable direct range entry at the pan/zoom drag points (drag
handles must be enabled above).
- showLink (boolean; optional):
Link to open this plot in plotly.
- sendData (boolean; optional):
If we show a link, does it contain data or just link to a
plotly file?.
- linkText (string; optional):
Text appearing in the sendData link.
- displayModeBar (a value equal to: true, false, 'hover'; optional):
Display the mode bar (True, False, or 'hover').
- showSendToCloud (boolean; optional):
Should we include a modebar button to send this data to a
Plotly Cloud instance, linked by `plotlyServerURL`. By default
this is False.
- showEditInChartStudio (boolean; optional):
Should we show a modebar button to send this data to a Plotly
Chart Studio plot. If both this and showSendToCloud are
selected, only showEditInChartStudio will be honored. By
default this is False.
- modeBarButtonsToRemove (list; optional):
Remove mode bar button by name. All modebar button names at
https://github.com/plotly/plotly.js/blob/master/src/components/modebar/buttons.js
Common names include: sendDataToCloud; (2D) zoom2d, pan2d,
select2d, lasso2d, zoomIn2d, zoomOut2d, autoScale2d,
resetScale2d; (Cartesian) hoverClosestCartesian,
hoverCompareCartesian; (3D) zoom3d, pan3d, orbitRotation,
tableRotation, handleDrag3d, resetCameraDefault3d,
resetCameraLastSave3d, hoverClosest3d; (Geo) zoomInGeo,
zoomOutGeo, resetGeo, hoverClosestGeo; hoverClosestGl2d,
hoverClosestPie, toggleHover, resetViews.
- modeBarButtonsToAdd (list; optional):
Add mode bar button using config objects.
- modeBarButtons (boolean | number | string | dict | list; optional):
Fully custom mode bar buttons as nested array, where the outer
arrays represents button groups, and the inner arrays have
buttons config objects or names of default buttons.
- toImageButtonOptions (dict; optional):
Modifications to how the toImage modebar button works.
`toImageButtonOptions` is a dict with keys:
- format (a value equal to: 'jpeg', 'png', 'webp', 'svg'; optional):
The file format to create.
- filename (string; optional):
The name given to the downloaded file.
- width (number; optional):
Width of the downloaded file, in px.
- height (number; optional):
Height of the downloaded file, in px.
- scale (number; optional):
Extra resolution to give the file after rendering it with
the given width and height.
- displaylogo (boolean; optional):
Add the plotly logo on the end of the mode bar.
- watermark (boolean; optional):
Add the plotly logo even with no modebar.
- plotGlPixelRatio (number; optional):
Increase the pixel ratio for Gl plot images.
- topojsonURL (string; optional):
URL to topojson files used in geo charts.
- mapboxAccessToken (boolean | number | string | dict | list; optional):
Mapbox access token (required to plot mapbox trace types) If
using an Mapbox Atlas server, set this option to '', so that
plotly.js won't attempt to authenticate to the public Mapbox
server.
- locale (string; optional):
The locale to use. Locales may be provided with the plot
(`locales` below) or by loading them on the page, see:
https://github.com/plotly/plotly.js/blob/master/dist/README.md#to-include-localization.
- locales (dict; optional):
Localization definitions, if you choose to provide them with
the plot rather than registering them globally.
- extendData (list | dict; optional):
Data that should be appended to existing traces. Has the form
`[updateData, traceIndices, maxPoints]`, where `updateData` is an
object containing the data to extend, `traceIndices` (optional) is
an array of trace indices that should be extended, and `maxPoints`
(optional) is either an integer defining the maximum number of
points allowed or an object with key:value pairs matching
`updateData` Reference the Plotly.extendTraces API for full usage:
https://plotly.com/javascript/plotlyjs-function-reference/#plotlyextendtraces.
- figure (dict; default { data: [], layout: {}, frames: [],}):
Plotly `figure` object. See schema:
https://plotly.com/javascript/reference `config` is set
separately by the `config` property.
`figure` is a dict with keys:
- data (list of dicts; optional)
- layout (dict; optional)
- frames (list of dicts; optional)
- hoverData (dict; optional):
Data from latest hover event. Read-only.
- mathjax (boolean; default False):
If True, loads mathjax v3 (tex-svg) into the page and use it in
the graph.
- prependData (list | dict; optional):
Data that should be prepended to existing traces. Has the form
`[updateData, traceIndices, maxPoints]`, where `updateData` is an
object containing the data to prepend, `traceIndices` (optional)
is an array of trace indices that should be prepended, and
`maxPoints` (optional) is either an integer defining the maximum
number of points allowed or an object with key:value pairs
matching `updateData` Reference the Plotly.prependTraces API for
full usage:
https://plotly.com/javascript/plotlyjs-function-reference/#plotlyprependtraces.
- relayoutData (dict; optional):
Data from latest relayout event which occurs when the user zooms
or pans on the plot or other layout-level edits. Has the form
`{<attr string>: <value>}` describing the changes made. Read-only.
- responsive (a value equal to: true, false, 'auto'; default 'auto'):
If True, the Plotly.js plot will be fully responsive to window
resize and parent element resize event. This is achieved by
overriding `config.responsive` to True, `figure.layout.autosize`
to True and unsetting `figure.layout.height` and
`figure.layout.width`. If False, the Plotly.js plot not be
responsive to window resize and parent element resize event. This
is achieved by overriding `config.responsive` to False and
`figure.layout.autosize` to False. If 'auto' (default), the Graph
will determine if the Plotly.js plot can be made fully responsive
(True) or not (False) based on the values in `config.responsive`,
`figure.layout.autosize`, `figure.layout.height`,
`figure.layout.width`. This is the legacy behavior of the Graph
component. Needs to be combined with appropriate dimension /
styling through the `style` prop to fully take effect.
- restyleData (list; optional):
Data from latest restyle event which occurs when the user toggles
a legend item, changes parcoords selections, or other trace-level
edits. Has the form `[edits, indices]`, where `edits` is an object
`{<attr string>: <value>}` describing the changes made, and
`indices` is an array of trace indices that were edited.
Read-only.
- selectedData (dict; optional):
Data from latest select event. Read-only."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Graph"
ConfigEdits = TypedDict(
"ConfigEdits",
{
"annotationPosition": NotRequired[bool],
"annotationTail": NotRequired[bool],
"annotationText": NotRequired[bool],
"axisTitleText": NotRequired[bool],
"colorbarPosition": NotRequired[bool],
"colorbarTitleText": NotRequired[bool],
"legendPosition": NotRequired[bool],
"legendText": NotRequired[bool],
"shapePosition": NotRequired[bool],
"titleText": NotRequired[bool],
},
)
ConfigToImageButtonOptions = TypedDict(
"ConfigToImageButtonOptions",
{
"format": NotRequired[Literal["jpeg", "png", "webp", "svg"]],
"filename": NotRequired[str],
"width": NotRequired[NumberType],
"height": NotRequired[NumberType],
"scale": NotRequired[NumberType],
},
)
Config = TypedDict(
"Config",
{
"staticPlot": NotRequired[bool],
"plotlyServerURL": NotRequired[str],
"editable": NotRequired[bool],
"editSelection": NotRequired[bool],
"edits": NotRequired["ConfigEdits"],
"autosizable": NotRequired[bool],
"responsive": NotRequired[bool],
"queueLength": NotRequired[NumberType],
"fillFrame": NotRequired[bool],
"frameMargins": NotRequired[NumberType],
"scrollZoom": NotRequired[bool],
"doubleClick": NotRequired[
Literal[False, "reset", "autosize", "reset+autosize"]
],
"doubleClickDelay": NotRequired[NumberType],
"showTips": NotRequired[bool],
"showAxisDragHandles": NotRequired[bool],
"showAxisRangeEntryBoxes": NotRequired[bool],
"showLink": NotRequired[bool],
"sendData": NotRequired[bool],
"linkText": NotRequired[str],
"displayModeBar": NotRequired[Literal[True, False, "hover"]],
"showSendToCloud": NotRequired[bool],
"showEditInChartStudio": NotRequired[bool],
"modeBarButtonsToRemove": NotRequired[typing.Sequence],
"modeBarButtonsToAdd": NotRequired[typing.Sequence],
"modeBarButtons": NotRequired[typing.Any],
"toImageButtonOptions": NotRequired["ConfigToImageButtonOptions"],
"displaylogo": NotRequired[bool],
"watermark": NotRequired[bool],
"plotGlPixelRatio": NotRequired[NumberType],
"topojsonURL": NotRequired[str],
"mapboxAccessToken": NotRequired[typing.Any],
"locale": NotRequired[str],
"locales": NotRequired[dict],
},
)
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
responsive: typing.Optional[Literal[True, False, "auto"]] = None,
clickData: typing.Optional[dict] = None,
clickAnnotationData: typing.Optional[dict] = None,
hoverData: typing.Optional[dict] = None,
clear_on_unhover: typing.Optional[bool] = None,
selectedData: typing.Optional[dict] = None,
relayoutData: typing.Optional[dict] = None,
extendData: typing.Optional[typing.Union[typing.Sequence, dict]] = None,
prependData: typing.Optional[typing.Union[typing.Sequence, dict]] = None,
restyleData: typing.Optional[typing.Sequence] = None,
figure: typing.Optional[typing.Union[Figure, dict]] = None,
style: typing.Optional[typing.Any] = None,
className: typing.Optional[str] = None,
mathjax: typing.Optional[bool] = None,
animate: typing.Optional[bool] = None,
animation_options: typing.Optional[dict] = None,
config: typing.Optional["Config"] = None,
**kwargs
):
self._prop_names = [
"id",
"animate",
"animation_options",
"className",
"clear_on_unhover",
"clickAnnotationData",
"clickData",
"config",
"extendData",
"figure",
"hoverData",
"mathjax",
"prependData",
"relayoutData",
"responsive",
"restyleData",
"selectedData",
"style",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"id",
"animate",
"animation_options",
"className",
"clear_on_unhover",
"clickAnnotationData",
"clickData",
"config",
"extendData",
"figure",
"hoverData",
"mathjax",
"prependData",
"relayoutData",
"responsive",
"restyleData",
"selectedData",
"style",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Graph, self).__init__(**args)
setattr(Graph, "__init__", _explicitize_args(Graph.__init__))
@@ -0,0 +1,399 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Input(Component):
"""An Input component.
A basic HTML input control for entering text, numbers, or passwords.
Note that checkbox and radio types are supported through
the Checklist and RadioItems component. Dates, times, and file uploads
are also supported through separate components.
Keyword arguments:
- value (string | number; optional):
The value of the input.
- type (a value equal to: 'text', 'number', 'password', 'email', 'range', 'search', 'tel', 'url', 'hidden'; default 'text'):
The type of control to render.
- debounce (boolean | number; default False):
If True, changes to input will be sent back to the Dash server
only on enter or when losing focus. If it's False, it will send
the value back on every change. If a number, it will not send
anything back to the Dash server until the user has stopped typing
for that number of seconds.
- placeholder (string | number; optional):
A hint to the user of what can be entered in the control . The
placeholder text must not contain carriage returns or line-feeds.
Note: Do not use the placeholder attribute instead of a <label>
element, their purposes are different. The <label> attribute
describes the role of the form element (i.e. it indicates what
kind of information is expected), and the placeholder attribute is
a hint about the format that the content should take. There are
cases in which the placeholder attribute is never displayed to the
user, so the form must be understandable without it.
- n_submit (number; default 0):
Number of times the `Enter` key was pressed while the input had
focus.
- n_submit_timestamp (number; default -1):
Last time that `Enter` was pressed.
- inputMode (a value equal to: 'verbatim', 'latin', 'latin-name', 'latin-prose', 'full-width-latin', 'kana', 'katakana', 'numeric', 'tel', 'email', 'url'; optional):
Provides a hint to the browser as to the type of data that might
be entered by the user while editing the element or its contents.
- autoComplete (string; optional):
This attribute indicates whether the value of the control can be
automatically completed by the browser.
- readOnly (boolean | a value equal to: 'readOnly', 'readonly', 'READONLY'; optional):
This attribute indicates that the user cannot modify the value of
the control. The value of the attribute is irrelevant. If you need
read-write access to the input value, do not add the \"readonly\"
attribute. It is ignored if the value of the type attribute is
hidden, range, color, checkbox, radio, file, or a button type
(such as button or submit). readOnly is an HTML boolean attribute
- it is enabled by a boolean or 'readOnly'. Alternative
capitalizations `readonly` & `READONLY` are also acccepted.
- required (a value equal to: 'required', 'REQUIRED' | boolean; optional):
This attribute specifies that the user must fill in a value before
submitting a form. It cannot be used when the type attribute is
hidden, image, or a button type (submit, reset, or button). The
:optional and :required CSS pseudo-classes will be applied to the
field as appropriate. required is an HTML boolean attribute - it
is enabled by a boolean or 'required'. Alternative capitalizations
`REQUIRED` are also acccepted.
- autoFocus (a value equal to: 'autoFocus', 'autofocus', 'AUTOFOCUS' | boolean; optional):
The element should be automatically focused after the page loaded.
autoFocus is an HTML boolean attribute - it is enabled by a
boolean or 'autoFocus'. Alternative capitalizations `autofocus` &
`AUTOFOCUS` are also acccepted.
- disabled (a value equal to: 'disabled', 'DISABLED' | boolean; optional):
If True, the input is disabled and can't be clicked on. disabled
is an HTML boolean attribute - it is enabled by a boolean or
'disabled'. Alternative capitalizations `DISABLED`.
- list (string; optional):
Identifies a list of pre-defined options to suggest to the user.
The value must be the id of a <datalist> element in the same
document. The browser displays only options that are valid values
for this input element. This attribute is ignored when the type
attribute's value is hidden, checkbox, radio, file, or a button
type.
- multiple (boolean; optional):
This Boolean attribute indicates whether the user can enter more
than one value. This attribute applies when the type attribute is
set to email or file, otherwise it is ignored.
- spellCheck (a value equal to: 'true', 'false' | boolean; optional):
Setting the value of this attribute to True indicates that the
element needs to have its spelling and grammar checked. The value
default indicates that the element is to act according to a
default behavior, possibly based on the parent element's own
spellcheck value. The value False indicates that the element
should not be checked.
- name (string; optional):
The name of the control, which is submitted with the form data.
- min (string | number; optional):
The minimum (numeric or date-time) value for this item, which must
not be greater than its maximum (max attribute) value.
- max (string | number; optional):
The maximum (numeric or date-time) value for this item, which must
not be less than its minimum (min attribute) value.
- step (string | number; default 'any'):
Works with the min and max attributes to limit the increments at
which a numeric or date-time value can be set. It can be the
string any or a positive floating point number. If this attribute
is not set to any, the control accepts only values at multiples of
the step value greater than the minimum.
- minLength (string | number; optional):
If the value of the type attribute is text, email, search,
password, tel, or url, this attribute specifies the minimum number
of characters (in Unicode code points) that the user can enter.
For other control types, it is ignored.
- maxLength (string | number; optional):
If the value of the type attribute is text, email, search,
password, tel, or url, this attribute specifies the maximum number
of characters (in UTF-16 code units) that the user can enter. For
other control types, it is ignored. It can exceed the value of the
size attribute. If it is not specified, the user can enter an
unlimited number of characters. Specifying a negative number
results in the default behavior (i.e. the user can enter an
unlimited number of characters). The constraint is evaluated only
when the value of the attribute has been changed.
- pattern (string; optional):
A regular expression that the control's value is checked against.
The pattern must match the entire value, not just some subset. Use
the title attribute to describe the pattern to help the user. This
attribute applies when the value of the type attribute is text,
search, tel, url, email, or password, otherwise it is ignored. The
regular expression language is the same as JavaScript RegExp
algorithm, with the 'u' parameter that makes it treat the pattern
as a sequence of unicode code points. The pattern is not
surrounded by forward slashes.
- selectionStart (string; optional):
The offset into the element's text content of the first selected
character. If there's no selection, this value indicates the
offset to the character following the current text input cursor
position (that is, the position the next character typed would
occupy).
- selectionEnd (string; optional):
The offset into the element's text content of the last selected
character. If there's no selection, this value indicates the
offset to the character following the current text input cursor
position (that is, the position the next character typed would
occupy).
- selectionDirection (string; optional):
The direction in which selection occurred. This is \"forward\" if
the selection was made from left-to-right in an LTR locale or
right-to-left in an RTL locale, or \"backward\" if the selection
was made in the opposite direction. On platforms on which it's
possible this value isn't known, the value can be \"none\"; for
example, on macOS, the default direction is \"none\", then as the
user begins to modify the selection using the keyboard, this will
change to reflect the direction in which the selection is
expanding.
- n_blur (number; default 0):
Number of times the input lost focus.
- n_blur_timestamp (number; default -1):
Last time the input lost focus.
- size (string; optional):
The initial size of the control. This value is in pixels unless
the value of the type attribute is text or password, in which case
it is an integer number of characters. Starting in, this attribute
applies only when the type attribute is set to text, search, tel,
url, email, or password, otherwise it is ignored. In addition, the
size must be greater than zero. If you do not specify a size, a
default value of 20 is used.' simply states \"the user agent
should ensure that at least that many characters are visible\",
but different characters can have different widths in certain
fonts. In some browsers, a certain string with x characters will
not be entirely visible even if size is defined to at least x.
- className (string; optional):
The class of the input element.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `value` that
the user has changed while using the app will keep that change, as
long as the new `value` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persisted_props (list of a value equal to: 'value's; default ['value']):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `value` is allowed this prop
can normally be ignored.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Input"
def __init__(
self,
value: typing.Optional[typing.Union[str, NumberType]] = None,
type: typing.Optional[
Literal[
"text",
"number",
"password",
"email",
"range",
"search",
"tel",
"url",
"hidden",
]
] = None,
debounce: typing.Optional[typing.Union[bool, NumberType]] = None,
placeholder: typing.Optional[typing.Union[str, NumberType]] = None,
n_submit: typing.Optional[NumberType] = None,
n_submit_timestamp: typing.Optional[NumberType] = None,
inputMode: typing.Optional[
Literal[
"verbatim",
"latin",
"latin-name",
"latin-prose",
"full-width-latin",
"kana",
"katakana",
"numeric",
"tel",
"email",
"url",
]
] = None,
autoComplete: typing.Optional[str] = None,
readOnly: typing.Optional[
typing.Union[bool, Literal["readOnly", "readonly", "READONLY"]]
] = None,
required: typing.Optional[
typing.Union[Literal["required", "REQUIRED"], bool]
] = None,
autoFocus: typing.Optional[
typing.Union[Literal["autoFocus", "autofocus", "AUTOFOCUS"], bool]
] = None,
disabled: typing.Optional[
typing.Union[Literal["disabled", "DISABLED"], bool]
] = None,
list: typing.Optional[str] = None,
multiple: typing.Optional[bool] = None,
spellCheck: typing.Optional[
typing.Union[Literal["true", "false"], bool]
] = None,
name: typing.Optional[str] = None,
min: typing.Optional[typing.Union[str, NumberType]] = None,
max: typing.Optional[typing.Union[str, NumberType]] = None,
step: typing.Optional[typing.Union[str, NumberType]] = None,
minLength: typing.Optional[typing.Union[str, NumberType]] = None,
maxLength: typing.Optional[typing.Union[str, NumberType]] = None,
pattern: typing.Optional[str] = None,
selectionStart: typing.Optional[str] = None,
selectionEnd: typing.Optional[str] = None,
selectionDirection: typing.Optional[str] = None,
n_blur: typing.Optional[NumberType] = None,
n_blur_timestamp: typing.Optional[NumberType] = None,
size: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
className: typing.Optional[str] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["value"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"value",
"type",
"debounce",
"placeholder",
"n_submit",
"n_submit_timestamp",
"inputMode",
"autoComplete",
"readOnly",
"required",
"autoFocus",
"disabled",
"list",
"multiple",
"spellCheck",
"name",
"min",
"max",
"step",
"minLength",
"maxLength",
"pattern",
"selectionStart",
"selectionEnd",
"selectionDirection",
"n_blur",
"n_blur_timestamp",
"size",
"style",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"value",
"type",
"debounce",
"placeholder",
"n_submit",
"n_submit_timestamp",
"inputMode",
"autoComplete",
"readOnly",
"required",
"autoFocus",
"disabled",
"list",
"multiple",
"spellCheck",
"name",
"min",
"max",
"step",
"minLength",
"maxLength",
"pattern",
"selectionStart",
"selectionEnd",
"selectionDirection",
"n_blur",
"n_blur_timestamp",
"size",
"style",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Input, self).__init__(**args)
setattr(Input, "__init__", _explicitize_args(Input.__init__))
@@ -0,0 +1,88 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Interval(Component):
"""An Interval component.
A component that repeatedly increments a counter `n_intervals`
with a fixed time delay between each increment.
Interval is good for triggering a component on a recurring basis.
The time delay is set with the property "interval" in milliseconds.
Keyword arguments:
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- disabled (boolean; optional):
If True, the counter will no longer update.
- interval (number; default 1000):
This component will increment the counter `n_intervals` every
`interval` milliseconds.
- max_intervals (number; default -1):
Number of times the interval will be fired. If -1, then the
interval has no limit (the default) and if 0 then the interval
stops running.
- n_intervals (number; default 0):
Number of times the interval has passed."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Interval"
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
interval: typing.Optional[NumberType] = None,
disabled: typing.Optional[bool] = None,
n_intervals: typing.Optional[NumberType] = None,
max_intervals: typing.Optional[NumberType] = None,
**kwargs
):
self._prop_names = [
"id",
"disabled",
"interval",
"max_intervals",
"n_intervals",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"id",
"disabled",
"interval",
"max_intervals",
"n_intervals",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Interval, self).__init__(**args)
setattr(Interval, "__init__", _explicitize_args(Interval.__init__))
@@ -0,0 +1,132 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Link(Component):
"""A Link component.
Link allows you to create a clickable link within a multi-page app.
For links with destinations outside the current app, `html.A` is a better
component to use.
Keyword arguments:
- children (a list of or a singular dash component, string or number; optional):
The children of this component.
- href (string; required):
The URL of a linked resource.
- target (string; optional):
Specifies where to open the link reference.
- refresh (boolean; default False):
Controls whether or not the page will refresh when the link is
clicked.
- title (string; optional):
Adds the title attribute to your link, which can contain
supplementary information.
- className (string; optional):
Often used with CSS to style elements with common properties.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- loading_state (dict; optional):
Object that holds the loading state object coming from
dash-renderer.
`loading_state` is a dict with keys:
- is_loading (boolean; optional):
Determines if the component is loading or not.
- prop_name (string; optional):
Holds which property is loading.
- component_name (string; optional):
Holds the name of the component that is loading."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Link"
LoadingState = TypedDict(
"LoadingState",
{
"is_loading": NotRequired[bool],
"prop_name": NotRequired[str],
"component_name": NotRequired[str],
},
)
def __init__(
self,
children: typing.Optional[ComponentType] = None,
href: typing.Optional[str] = None,
target: typing.Optional[str] = None,
refresh: typing.Optional[bool] = None,
title: typing.Optional[str] = None,
className: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
loading_state: typing.Optional["LoadingState"] = None,
**kwargs
):
self._prop_names = [
"children",
"href",
"target",
"refresh",
"title",
"className",
"style",
"id",
"loading_state",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"children",
"href",
"target",
"refresh",
"title",
"className",
"style",
"id",
"loading_state",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args if k != "children"}
for k in ["href"]:
if k not in args:
raise TypeError("Required argument `" + k + "` was not specified.")
super(Link, self).__init__(children=children, **args)
setattr(Link, "__init__", _explicitize_args(Link.__init__))
@@ -0,0 +1,171 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Loading(Component):
"""A Loading component.
Keyword arguments:
- children (list of a list of or a singular dash component, string or numbers | a list of or a singular dash component, string or number; optional):
Array that holds components to render.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- className (string; optional):
Additional CSS class for the built-in spinner root DOM node.
- color (string; default '#119DFF'):
Primary color used for the built-in loading spinners.
- custom_spinner (a list of or a singular dash component, string or number; optional):
Component to use rather than the built-in spinner specified in the
`type` prop.
- debug (boolean; optional):
If True, the built-in spinner will display the component_name and
prop_name while loading.
- delay_hide (number; default 0):
Add a time delay (in ms) to the spinner being removed to prevent
flickering.
- delay_show (number; default 0):
Add a time delay (in ms) to the spinner being shown after the
loading_state is set to True.
- display (a value equal to: 'auto', 'show', 'hide'; default 'auto'):
Setting display to \"show\" or \"hide\" will override the
loading state coming from dash-renderer.
- fullscreen (boolean; optional):
Boolean that makes the built-in spinner display full-screen.
- overlay_style (dict; optional):
Additional CSS styling for the spinner overlay. This is applied to
the dcc.Loading children while the spinner is active. The default
is `{'visibility': 'hidden'}`.
- parent_className (string; optional):
Additional CSS class for the outermost dcc.Loading parent div DOM
node.
- parent_style (dict; optional):
Additional CSS styling for the outermost dcc.Loading parent div
DOM node.
- show_initially (boolean; default True):
Whether the Spinner should show on app start-up before the loading
state has been determined. Default True. Use when also setting
`delay_show`.
- target_components (dict with strings as keys and values of type string | list of strings; optional):
Specify component and prop to trigger showing the loading spinner
example: `{\"output-container\": \"children\", \"grid\":
[\"rowData\", \"columnDefs]}`.
- type (a value equal to: 'graph', 'cube', 'circle', 'dot', 'default'; optional):
Property that determines which built-in spinner to show one of
'graph', 'cube', 'circle', 'dot', or 'default'."""
_children_props = ["custom_spinner"]
_base_nodes = ["custom_spinner", "children"]
_namespace = "dash_core_components"
_type = "Loading"
def __init__(
self,
children: typing.Optional[ComponentType] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
type: typing.Optional[
Literal["graph", "cube", "circle", "dot", "default"]
] = None,
fullscreen: typing.Optional[bool] = None,
debug: typing.Optional[bool] = None,
className: typing.Optional[str] = None,
parent_className: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
parent_style: typing.Optional[dict] = None,
overlay_style: typing.Optional[dict] = None,
color: typing.Optional[str] = None,
display: typing.Optional[Literal["auto", "show", "hide"]] = None,
delay_hide: typing.Optional[NumberType] = None,
delay_show: typing.Optional[NumberType] = None,
show_initially: typing.Optional[bool] = None,
target_components: typing.Optional[
typing.Dict[
typing.Union[str, float, int], typing.Union[str, typing.Sequence[str]]
]
] = None,
custom_spinner: typing.Optional[ComponentType] = None,
**kwargs
):
self._prop_names = [
"children",
"id",
"className",
"color",
"custom_spinner",
"debug",
"delay_hide",
"delay_show",
"display",
"fullscreen",
"overlay_style",
"parent_className",
"parent_style",
"show_initially",
"style",
"target_components",
"type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"children",
"id",
"className",
"color",
"custom_spinner",
"debug",
"delay_hide",
"delay_show",
"display",
"fullscreen",
"overlay_style",
"parent_className",
"parent_style",
"show_initially",
"style",
"target_components",
"type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args if k != "children"}
super(Loading, self).__init__(children=children, **args)
setattr(Loading, "__init__", _explicitize_args(Loading.__init__))
@@ -0,0 +1,94 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Location(Component):
"""A Location component.
Update and track the current window.location object through the window.history state.
Use in conjunction with the `dash_core_components.Link` component to make apps with multiple pages.
Keyword arguments:
- id (string; required):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- hash (string; optional):
hash in window.location - e.g., \"#myhash\".
- href (string; optional):
href in window.location - e.g.,
\"/my/full/pathname?myargument=1#myhash\".
- pathname (string; optional):
pathname in window.location - e.g., \"/my/full/pathname\".
- refresh (a value equal to: 'callback-nav' | boolean; default True):
Use `True` to navigate outside the Dash app or to manually refresh
a page. Use `False` if the same callback that updates the Location
component is also updating the page content - typically used in
multi-page apps that do not use Pages. Use 'callback-nav' if you
are updating the URL in a callback, or a different callback will
respond to the new Location with updated content. This is typical
with multi-page apps that use Pages. This will allow for
navigating to a new page without refreshing the page.
- search (string; optional):
search in window.location - e.g., \"?myargument=1\"."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Location"
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
pathname: typing.Optional[str] = None,
search: typing.Optional[str] = None,
hash: typing.Optional[str] = None,
href: typing.Optional[str] = None,
refresh: typing.Optional[typing.Union[Literal["callback-nav"], bool]] = None,
**kwargs
):
self._prop_names = ["id", "hash", "href", "pathname", "refresh", "search"]
self._valid_wildcard_attributes = []
self.available_properties = [
"id",
"hash",
"href",
"pathname",
"refresh",
"search",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
for k in ["id"]:
if k not in args:
raise TypeError("Required argument `" + k + "` was not specified.")
super(Location, self).__init__(**args)
setattr(Location, "__init__", _explicitize_args(Location.__init__))
@@ -0,0 +1,122 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Markdown(Component):
"""A Markdown component.
A component that renders Markdown text as specified by the
GitHub Markdown spec. These component uses
[react-markdown](https://rexxars.github.io/react-markdown/) under the hood.
Keyword arguments:
- children (string | list of strings; optional):
A markdown string (or array of strings) that adheres to the
CommonMark spec.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- className (string; optional):
Class name of the container element.
- dangerously_allow_html (boolean; default False):
A boolean to control raw HTML escaping. Setting HTML from code is
risky because it's easy to inadvertently expose your users to a
cross-site scripting (XSS)
(https://en.wikipedia.org/wiki/Cross-site_scripting) attack.
- dedent (boolean; default True):
Remove matching leading whitespace from all lines. Lines that are
empty, or contain *only* whitespace, are ignored. Both spaces and
tab characters are removed, but only if they match; we will not
convert tabs to spaces or vice versa.
- highlight_config (dict; optional):
Config options for syntax highlighting.
`highlight_config` is a dict with keys:
- theme (a value equal to: 'dark', 'light'; optional):
Color scheme; default 'light'.
- link_target (string; optional):
A string for the target attribute to use on links (such as
\"_blank\").
- mathjax (boolean; default False):
If True, loads mathjax v3 (tex-svg) into the page and use it in
the markdown."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Markdown"
HighlightConfig = TypedDict(
"HighlightConfig", {"theme": NotRequired[Literal["dark", "light"]]}
)
def __init__(
self,
children: typing.Optional[ComponentType] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
className: typing.Optional[str] = None,
mathjax: typing.Optional[bool] = None,
dangerously_allow_html: typing.Optional[bool] = None,
link_target: typing.Optional[str] = None,
dedent: typing.Optional[bool] = None,
highlight_config: typing.Optional["HighlightConfig"] = None,
style: typing.Optional[typing.Any] = None,
**kwargs
):
self._prop_names = [
"children",
"id",
"className",
"dangerously_allow_html",
"dedent",
"highlight_config",
"link_target",
"mathjax",
"style",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"children",
"id",
"className",
"dangerously_allow_html",
"dedent",
"highlight_config",
"link_target",
"mathjax",
"style",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args if k != "children"}
super(Markdown, self).__init__(children=children, **args)
setattr(Markdown, "__init__", _explicitize_args(Markdown.__init__))
@@ -0,0 +1,177 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class RadioItems(Component):
"""A RadioItems component.
RadioItems is a component that encapsulates several radio item inputs.
The values and labels of the RadioItems is specified in the `options`
property and the seleced item is specified with the `value` property.
Each radio item is rendered as an input with a surrounding label.
Keyword arguments:
- options (list of dicts; optional):
An array of options, or inline dictionary of options.
`options` is a list of string | number | booleans | dict | list of
dicts with keys:
- label (a list of or a singular dash component, string or number; required):
The option's label.
- value (string | number | boolean; required):
The value of the option. This value corresponds to the items
specified in the `value` property.
- disabled (boolean; optional):
If True, this option is disabled and cannot be selected.
- title (string; optional):
The HTML 'title' attribute for the option. Allows for
information on hover. For more information on this attribute,
see
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title.
- value (string | number | boolean; optional):
The currently selected value.
- inline (boolean; default False):
Indicates whether the options labels should be displayed inline
(True=horizontal) or in a block (False=vertical).
- className (string; optional):
The class of the container (div).
- inputStyle (dict; optional):
The style of the <input> radio element.
- inputClassName (string; default ''):
The class of the <input> radio element.
- labelStyle (dict; optional):
The style of the <label> that wraps the radio input and the
option's label.
- labelClassName (string; default ''):
The class of the <label> that wraps the radio input and the
option's label.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `value` that
the user has changed while using the app will keep that change, as
long as the new `value` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persisted_props (list of a value equal to: 'value's; default ['value']):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `value` is allowed this prop
can normally be ignored.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit."""
_children_props = ["options[].label"]
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "RadioItems"
Options = TypedDict(
"Options",
{
"label": ComponentType,
"value": typing.Union[str, NumberType, bool],
"disabled": NotRequired[bool],
"title": NotRequired[str],
},
)
def __init__(
self,
options: typing.Optional[
typing.Union[
typing.Sequence[typing.Union[str, NumberType, bool]],
dict,
typing.Sequence["Options"],
]
] = None,
value: typing.Optional[typing.Union[str, NumberType, bool]] = None,
inline: typing.Optional[bool] = None,
style: typing.Optional[typing.Any] = None,
className: typing.Optional[str] = None,
inputStyle: typing.Optional[dict] = None,
inputClassName: typing.Optional[str] = None,
labelStyle: typing.Optional[dict] = None,
labelClassName: typing.Optional[str] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["value"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"options",
"value",
"inline",
"style",
"className",
"inputStyle",
"inputClassName",
"labelStyle",
"labelClassName",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"options",
"value",
"inline",
"style",
"className",
"inputStyle",
"inputClassName",
"labelStyle",
"labelClassName",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(RadioItems, self).__init__(**args)
setattr(RadioItems, "__init__", _explicitize_args(RadioItems.__init__))
@@ -0,0 +1,263 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class RangeSlider(Component):
"""A RangeSlider component.
A double slider with two handles.
Used for specifying a range of numerical values.
Keyword arguments:
- min (number; optional):
Minimum allowed value of the slider.
- max (number; optional):
Maximum allowed value of the slider.
- step (number; optional):
Value by which increments or decrements are made.
- marks (dict; optional):
Marks on the slider. The key determines the position (a number),
and the value determines what will show. If you want to set the
style of a specific mark point, the value should be an object
which contains style and label properties.
`marks` is a dict with strings as keys and values of type string |
dict with keys:
- label (string; optional)
- style (dict; optional)
- value (list of numbers; optional):
The value of the input.
- drag_value (list of numbers; optional):
The value of the input during a drag.
- allowCross (boolean; optional):
allowCross could be set as True to allow those handles to cross.
- pushable (boolean | number; optional):
pushable could be set as True to allow pushing of surrounding
handles when moving an handle. When set to a number, the number
will be the minimum ensured distance between handles.
- disabled (boolean; optional):
If True, the handles can't be moved.
- count (number; optional):
Determine how many ranges to render, and multiple handles will be
rendered (number + 1).
- dots (boolean; optional):
When the step value is greater than 1, you can set the dots to
True if you want to render the slider with dots.
- included (boolean; optional):
If the value is True, it means a continuous value is included.
Otherwise, it is an independent value.
- tooltip (dict; optional):
Configuration for tooltips describing the current slider values.
`tooltip` is a dict with keys:
- always_visible (boolean; optional):
Determines whether tooltips should always be visible (as
opposed to the default, visible on hover).
- placement (a value equal to: 'left', 'right', 'top', 'bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'; optional):
Determines the placement of tooltips See
https://github.com/react-component/tooltip#api top/bottom{*}
sets the _origin_ of the tooltip, so e.g. `topLeft` will in
reality appear to be on the top right of the handle.
- template (string; optional):
Template string to display the tooltip in. Must contain
`{value}`, which will be replaced with either the default
string representation of the value or the result of the
transform function if there is one.
- style (dict; optional):
Custom style for the tooltip.
- transform (string; optional):
Reference to a function in the `window.dccFunctions`
namespace. This can be added in a script in the asset folder.
For example, in `assets/tooltip.js`: ``` window.dccFunctions =
window.dccFunctions || {}; window.dccFunctions.multByTen =
function(value) { return value * 10; } ``` Then in the
component `tooltip={'transform': 'multByTen'}`.
- updatemode (a value equal to: 'mouseup', 'drag'; default 'mouseup'):
Determines when the component should update its `value` property.
If `mouseup` (the default) then the slider will only trigger its
value when the user has finished dragging the slider. If `drag`,
then the slider will update its value continuously as it is being
dragged. Note that for the latter case, the `drag_value` property
could be used instead.
- vertical (boolean; optional):
If True, the slider will be vertical.
- verticalHeight (number; default 400):
The height, in px, of the slider if it is vertical.
- className (string; optional):
Additional CSS class for the root DOM node.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `value` that
the user has changed while using the app will keep that change, as
long as the new `value` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persisted_props (list of a value equal to: 'value's; default ['value']):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `value` is allowed this prop
can normally be ignored.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "RangeSlider"
Marks = TypedDict("Marks", {"label": NotRequired[str], "style": NotRequired[dict]})
Tooltip = TypedDict(
"Tooltip",
{
"always_visible": NotRequired[bool],
"placement": NotRequired[
Literal[
"left",
"right",
"top",
"bottom",
"topLeft",
"topRight",
"bottomLeft",
"bottomRight",
]
],
"template": NotRequired[str],
"style": NotRequired[dict],
"transform": NotRequired[str],
},
)
def __init__(
self,
min: typing.Optional[NumberType] = None,
max: typing.Optional[NumberType] = None,
step: typing.Optional[NumberType] = None,
marks: typing.Optional[
typing.Dict[typing.Union[str, float, int], typing.Union[str, "Marks"]]
] = None,
value: typing.Optional[typing.Sequence[NumberType]] = None,
drag_value: typing.Optional[typing.Sequence[NumberType]] = None,
allowCross: typing.Optional[bool] = None,
pushable: typing.Optional[typing.Union[bool, NumberType]] = None,
disabled: typing.Optional[bool] = None,
count: typing.Optional[NumberType] = None,
dots: typing.Optional[bool] = None,
included: typing.Optional[bool] = None,
tooltip: typing.Optional["Tooltip"] = None,
updatemode: typing.Optional[Literal["mouseup", "drag"]] = None,
vertical: typing.Optional[bool] = None,
verticalHeight: typing.Optional[NumberType] = None,
className: typing.Optional[str] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["value"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"min",
"max",
"step",
"marks",
"value",
"drag_value",
"allowCross",
"pushable",
"disabled",
"count",
"dots",
"included",
"tooltip",
"updatemode",
"vertical",
"verticalHeight",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"min",
"max",
"step",
"marks",
"value",
"drag_value",
"allowCross",
"pushable",
"disabled",
"count",
"dots",
"included",
"tooltip",
"updatemode",
"vertical",
"verticalHeight",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(RangeSlider, self).__init__(**args)
setattr(RangeSlider, "__init__", _explicitize_args(RangeSlider.__init__))
@@ -0,0 +1,242 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Slider(Component):
"""A Slider component.
A slider component with a single handle.
Keyword arguments:
- min (number; optional):
Minimum allowed value of the slider.
- max (number; optional):
Maximum allowed value of the slider.
- step (number; optional):
Value by which increments or decrements are made.
- marks (dict; optional):
Marks on the slider. The key determines the position (a number),
and the value determines what will show. If you want to set the
style of a specific mark point, the value should be an object
which contains style and label properties.
`marks` is a dict with strings as keys and values of type string |
dict with keys:
- label (string; optional)
- style (dict; optional)
- value (number; optional):
The value of the input.
- drag_value (number; optional):
The value of the input during a drag.
- disabled (boolean; optional):
If True, the handles can't be moved.
- dots (boolean; optional):
When the step value is greater than 1, you can set the dots to
True if you want to render the slider with dots.
- included (boolean; optional):
If the value is True, it means a continuous value is included.
Otherwise, it is an independent value.
- tooltip (dict; optional):
Configuration for tooltips describing the current slider value.
`tooltip` is a dict with keys:
- always_visible (boolean; optional):
Determines whether tooltips should always be visible (as
opposed to the default, visible on hover).
- placement (a value equal to: 'left', 'right', 'top', 'bottom', 'topLeft', 'topRight', 'bottomLeft', 'bottomRight'; optional):
Determines the placement of tooltips See
https://github.com/react-component/tooltip#api top/bottom{*}
sets the _origin_ of the tooltip, so e.g. `topLeft` will in
reality appear to be on the top right of the handle.
- template (string; optional):
Template string to display the tooltip in. Must contain
`{value}`, which will be replaced with either the default
string representation of the value or the result of the
transform function if there is one.
- style (dict; optional):
Custom style for the tooltip.
- transform (string; optional):
Reference to a function in the `window.dccFunctions`
namespace. This can be added in a script in the asset folder.
For example, in `assets/tooltip.js`: ``` window.dccFunctions =
window.dccFunctions || {}; window.dccFunctions.multByTen =
function(value) { return value * 10; } ``` Then in the
component `tooltip={'transform': 'multByTen'}`.
- updatemode (a value equal to: 'mouseup', 'drag'; default 'mouseup'):
Determines when the component should update its `value` property.
If `mouseup` (the default) then the slider will only trigger its
value when the user has finished dragging the slider. If `drag`,
then the slider will update its value continuously as it is being
dragged. If you want different actions during and after drag,
leave `updatemode` as `mouseup` and use `drag_value` for the
continuously updating value.
- vertical (boolean; optional):
If True, the slider will be vertical.
- verticalHeight (number; default 400):
The height, in px, of the slider if it is vertical.
- className (string; optional):
Additional CSS class for the root DOM node.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `value` that
the user has changed while using the app will keep that change, as
long as the new `value` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persisted_props (list of a value equal to: 'value's; default ['value']):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `value` is allowed this prop
can normally be ignored.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Slider"
Marks = TypedDict("Marks", {"label": NotRequired[str], "style": NotRequired[dict]})
Tooltip = TypedDict(
"Tooltip",
{
"always_visible": NotRequired[bool],
"placement": NotRequired[
Literal[
"left",
"right",
"top",
"bottom",
"topLeft",
"topRight",
"bottomLeft",
"bottomRight",
]
],
"template": NotRequired[str],
"style": NotRequired[dict],
"transform": NotRequired[str],
},
)
def __init__(
self,
min: typing.Optional[NumberType] = None,
max: typing.Optional[NumberType] = None,
step: typing.Optional[NumberType] = None,
marks: typing.Optional[
typing.Dict[typing.Union[str, float, int], typing.Union[str, "Marks"]]
] = None,
value: typing.Optional[NumberType] = None,
drag_value: typing.Optional[NumberType] = None,
disabled: typing.Optional[bool] = None,
dots: typing.Optional[bool] = None,
included: typing.Optional[bool] = None,
tooltip: typing.Optional["Tooltip"] = None,
updatemode: typing.Optional[Literal["mouseup", "drag"]] = None,
vertical: typing.Optional[bool] = None,
verticalHeight: typing.Optional[NumberType] = None,
className: typing.Optional[str] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["value"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"min",
"max",
"step",
"marks",
"value",
"drag_value",
"disabled",
"dots",
"included",
"tooltip",
"updatemode",
"vertical",
"verticalHeight",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"min",
"max",
"step",
"marks",
"value",
"drag_value",
"disabled",
"dots",
"included",
"tooltip",
"updatemode",
"vertical",
"verticalHeight",
"className",
"id",
"persistence",
"persisted_props",
"persistence_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Slider, self).__init__(**args)
setattr(Slider, "__init__", _explicitize_args(Slider.__init__))
@@ -0,0 +1,94 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Store(Component):
"""A Store component.
Easily keep data on the client side with this component.
The data is not inserted in the DOM.
Data can be in memory, localStorage or sessionStorage.
The data will be kept with the id as key.
Keyword arguments:
- id (string; required):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- clear_data (boolean; default False):
Set to True to remove the data contained in `data_key`.
- data (dict | list | number | string | boolean; optional):
The stored data for the id.
- modified_timestamp (number; default -1):
The last time the storage was modified.
- storage_type (a value equal to: 'local', 'session', 'memory'; default 'memory'):
The type of the web storage. memory: only kept in memory, reset
on page refresh. local: window.localStorage, data is kept after
the browser quit. session: window.sessionStorage, data is cleared
once the browser quit."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Store"
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
storage_type: typing.Optional[Literal["local", "session", "memory"]] = None,
data: typing.Optional[
typing.Union[dict, typing.Sequence, NumberType, str, bool]
] = None,
clear_data: typing.Optional[bool] = None,
modified_timestamp: typing.Optional[NumberType] = None,
**kwargs
):
self._prop_names = [
"id",
"clear_data",
"data",
"modified_timestamp",
"storage_type",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"id",
"clear_data",
"data",
"modified_timestamp",
"storage_type",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
for k in ["id"]:
if k not in args:
raise TypeError("Required argument `" + k + "` was not specified.")
super(Store, self).__init__(**args)
setattr(Store, "__init__", _explicitize_args(Store.__init__))
@@ -0,0 +1,118 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Tab(Component):
"""A Tab component.
Part of dcc.Tabs - this is the child Tab component used to render a tabbed page.
Its children will be set as the content of that tab, which if clicked will become visible.
Keyword arguments:
- children (a list of or a singular dash component, string or number; optional):
The content of the tab - will only be displayed if this tab is
selected.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- className (string; optional):
Appends a class to the Tab component.
- disabled (boolean; default False):
Determines if tab is disabled or not - defaults to False.
- disabled_className (string; optional):
Appends a class to the Tab component when it is disabled.
- disabled_style (dict; default {color: '#d6d6d6'}):
Overrides the default (inline) styles when disabled.
- label (string; optional):
The tab's label.
- selected_className (string; optional):
Appends a class to the Tab component when it is selected.
- selected_style (dict; optional):
Overrides the default (inline) styles for the Tab component when
it is selected.
- value (string; optional):
Value for determining which Tab is currently selected."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Tab"
def __init__(
self,
children: typing.Optional[ComponentType] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
label: typing.Optional[str] = None,
value: typing.Optional[str] = None,
disabled: typing.Optional[bool] = None,
disabled_style: typing.Optional[dict] = None,
disabled_className: typing.Optional[str] = None,
className: typing.Optional[str] = None,
selected_className: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
selected_style: typing.Optional[dict] = None,
**kwargs
):
self._prop_names = [
"children",
"id",
"className",
"disabled",
"disabled_className",
"disabled_style",
"label",
"selected_className",
"selected_style",
"style",
"value",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"children",
"id",
"className",
"disabled",
"disabled_className",
"disabled_style",
"label",
"selected_className",
"selected_style",
"style",
"value",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args if k != "children"}
super(Tab, self).__init__(children=children, **args)
setattr(Tab, "__init__", _explicitize_args(Tab.__init__))
@@ -0,0 +1,176 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Tabs(Component):
"""A Tabs component.
A Dash component that lets you render pages with tabs - the Tabs component's children
can be dcc.Tab components, which can hold a label that will be displayed as a tab, and can in turn hold
children components that will be that tab's content.
Keyword arguments:
- children (list of a list of or a singular dash component, string or numbers | a list of or a singular dash component, string or number; optional):
Array that holds Tab components.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- className (string; optional):
Appends a class to the Tabs container holding the individual Tab
components.
- colors (dict; default { border: '#d6d6d6', primary: '#1975FA', background: '#f9f9f9',}):
Holds the colors used by the Tabs and Tab components. If you set
these, you should specify colors for all properties, so: colors: {
border: '#d6d6d6', primary: '#1975FA', background: '#f9f9f9'
}.
`colors` is a dict with keys:
- border (string; optional)
- primary (string; optional)
- background (string; optional)
- content_className (string; optional):
Appends a class to the Tab content container holding the children
of the Tab that is selected.
- content_style (dict; optional):
Appends (inline) styles to the tab content container holding the
children of the Tab that is selected.
- mobile_breakpoint (number; default 800):
Breakpoint at which tabs are rendered full width (can be 0 if you
don't want full width tabs on mobile).
- parent_className (string; optional):
Appends a class to the top-level parent container holding both the
Tabs container and the content container.
- parent_style (dict; optional):
Appends (inline) styles to the top-level parent container holding
both the Tabs container and the content container.
- persisted_props (list of a value equal to: 'value's; default ['value']):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `value` is allowed this prop
can normally be ignored.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `value` that
the user has changed while using the app will keep that change, as
long as the new `value` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persistence_type (a value equal to: 'local', 'session', 'memory'; default 'local'):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit.
- value (string; optional):
The value of the currently selected Tab.
- vertical (boolean; default False):
Renders the tabs vertically (on the side)."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Tabs"
Colors = TypedDict(
"Colors",
{
"border": NotRequired[str],
"primary": NotRequired[str],
"background": NotRequired[str],
},
)
def __init__(
self,
children: typing.Optional[ComponentType] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
value: typing.Optional[str] = None,
className: typing.Optional[str] = None,
content_className: typing.Optional[str] = None,
parent_className: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
parent_style: typing.Optional[dict] = None,
content_style: typing.Optional[dict] = None,
vertical: typing.Optional[bool] = None,
mobile_breakpoint: typing.Optional[NumberType] = None,
colors: typing.Optional["Colors"] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["value"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"children",
"id",
"className",
"colors",
"content_className",
"content_style",
"mobile_breakpoint",
"parent_className",
"parent_style",
"persisted_props",
"persistence",
"persistence_type",
"style",
"value",
"vertical",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"children",
"id",
"className",
"colors",
"content_className",
"content_style",
"mobile_breakpoint",
"parent_className",
"parent_style",
"persisted_props",
"persistence",
"persistence_type",
"style",
"value",
"vertical",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args if k != "children"}
super(Tabs, self).__init__(children=children, **args)
setattr(Tabs, "__init__", _explicitize_args(Tabs.__init__))
@@ -0,0 +1,275 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Textarea(Component):
"""A Textarea component.
A basic HTML textarea for entering multiline text.
Keyword arguments:
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- accessKey (string; optional):
Defines a keyboard shortcut to activate or add focus to the
element.
- autoFocus (string; optional):
The element should be automatically focused after the page loaded.
- className (string; optional):
Often used with CSS to style elements with common properties.
- cols (string | number; optional):
Defines the number of columns in a textarea.
- contentEditable (string | boolean; optional):
Indicates whether the element's content is editable.
- contextMenu (string; optional):
Defines the ID of a <menu> element which will serve as the
element's context menu.
- dir (string; optional):
Defines the text direction. Allowed values are ltr (Left-To-Right)
or rtl (Right-To-Left).
- disabled (string | boolean; optional):
Indicates whether the user can interact with the element.
- draggable (a value equal to: 'true', 'false' | boolean; optional):
Defines whether the element can be dragged.
- form (string; optional):
Indicates the form that is the owner of the element.
- hidden (string; optional):
Prevents rendering of given element, while keeping child elements,
e.g. script elements, active.
- lang (string; optional):
Defines the language used in the element.
- maxLength (string | number; optional):
Defines the maximum number of characters allowed in the element.
- minLength (string | number; optional):
Defines the minimum number of characters allowed in the element.
- n_blur (number; default 0):
Number of times the textarea lost focus.
- n_blur_timestamp (number; default -1):
Last time the textarea lost focus.
- n_clicks (number; optional):
Number of times the textarea has been clicked.
- n_clicks_timestamp (number; default -1):
Last time the textarea was clicked.
- name (string; optional):
Name of the element. For example used by the server to identify
the fields in form submits.
- persisted_props (list of a value equal to: 'value's; optional):
Properties whose user interactions will persist after refreshing
the component or the page. Since only `value` is allowed this prop
can normally be ignored.
- persistence (boolean | string | number; optional):
Used to allow user interactions in this component to be persisted
when the component - or the page - is refreshed. If `persisted` is
truthy and hasn't changed from its previous value, a `value` that
the user has changed while using the app will keep that change, as
long as the new `value` also matches what was given originally.
Used in conjunction with `persistence_type`.
- persistence_type (a value equal to: 'local', 'session', 'memory'; optional):
Where persisted user changes will be stored: memory: only kept in
memory, reset on page refresh. local: window.localStorage, data is
kept after the browser quit. session: window.sessionStorage, data
is cleared once the browser quit.
- placeholder (string; optional):
Provides a hint to the user of what can be entered in the field.
- readOnly (boolean | a value equal to: 'readOnly', 'readonly', 'READONLY'; optional):
Indicates whether the element can be edited. readOnly is an HTML
boolean attribute - it is enabled by a boolean or 'readOnly'.
Alternative capitalizations `readonly` & `READONLY` are also
acccepted.
- required (a value equal to: 'required', 'REQUIRED' | boolean; optional):
Indicates whether this element is required to fill out or not.
required is an HTML boolean attribute - it is enabled by a boolean
or 'required'. Alternative capitalizations `REQUIRED` are also
acccepted.
- rows (string | number; optional):
Defines the number of rows in a text area.
- spellCheck (a value equal to: 'true', 'false' | boolean; optional):
Indicates whether spell checking is allowed for the element.
- tabIndex (string | number; optional):
Overrides the browser's default tab order and follows the one
specified instead.
- title (string; optional):
Text to be displayed in a tooltip when hovering over the element.
- value (string; optional):
The value of the textarea.
- wrap (string; optional):
Indicates whether the text should be wrapped."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Textarea"
def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
value: typing.Optional[str] = None,
autoFocus: typing.Optional[str] = None,
cols: typing.Optional[typing.Union[str, NumberType]] = None,
disabled: typing.Optional[typing.Union[str, bool]] = None,
form: typing.Optional[str] = None,
maxLength: typing.Optional[typing.Union[str, NumberType]] = None,
minLength: typing.Optional[typing.Union[str, NumberType]] = None,
name: typing.Optional[str] = None,
placeholder: typing.Optional[str] = None,
readOnly: typing.Optional[
typing.Union[bool, Literal["readOnly", "readonly", "READONLY"]]
] = None,
required: typing.Optional[
typing.Union[Literal["required", "REQUIRED"], bool]
] = None,
rows: typing.Optional[typing.Union[str, NumberType]] = None,
wrap: typing.Optional[str] = None,
accessKey: typing.Optional[str] = None,
className: typing.Optional[str] = None,
contentEditable: typing.Optional[typing.Union[str, bool]] = None,
contextMenu: typing.Optional[str] = None,
dir: typing.Optional[str] = None,
draggable: typing.Optional[typing.Union[Literal["true", "false"], bool]] = None,
hidden: typing.Optional[str] = None,
lang: typing.Optional[str] = None,
spellCheck: typing.Optional[
typing.Union[Literal["true", "false"], bool]
] = None,
style: typing.Optional[typing.Any] = None,
tabIndex: typing.Optional[typing.Union[str, NumberType]] = None,
title: typing.Optional[str] = None,
n_blur: typing.Optional[NumberType] = None,
n_blur_timestamp: typing.Optional[NumberType] = None,
n_clicks: typing.Optional[NumberType] = None,
n_clicks_timestamp: typing.Optional[NumberType] = None,
persistence: typing.Optional[typing.Union[bool, str, NumberType]] = None,
persisted_props: typing.Optional[typing.Sequence[Literal["value"]]] = None,
persistence_type: typing.Optional[Literal["local", "session", "memory"]] = None,
**kwargs
):
self._prop_names = [
"id",
"accessKey",
"autoFocus",
"className",
"cols",
"contentEditable",
"contextMenu",
"dir",
"disabled",
"draggable",
"form",
"hidden",
"lang",
"maxLength",
"minLength",
"n_blur",
"n_blur_timestamp",
"n_clicks",
"n_clicks_timestamp",
"name",
"persisted_props",
"persistence",
"persistence_type",
"placeholder",
"readOnly",
"required",
"rows",
"spellCheck",
"style",
"tabIndex",
"title",
"value",
"wrap",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"id",
"accessKey",
"autoFocus",
"className",
"cols",
"contentEditable",
"contextMenu",
"dir",
"disabled",
"draggable",
"form",
"hidden",
"lang",
"maxLength",
"minLength",
"n_blur",
"n_blur_timestamp",
"n_clicks",
"n_clicks_timestamp",
"name",
"persisted_props",
"persistence",
"persistence_type",
"placeholder",
"readOnly",
"required",
"rows",
"spellCheck",
"style",
"tabIndex",
"title",
"value",
"wrap",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}
super(Textarea, self).__init__(**args)
setattr(Textarea, "__init__", _explicitize_args(Textarea.__init__))
@@ -0,0 +1,145 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Tooltip(Component):
"""A Tooltip component.
A tooltip with an absolute position.
Keyword arguments:
- children (a list of or a singular dash component, string or number; optional):
The contents of the tooltip.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- background_color (string; default 'white'):
Color of the tooltip background, as a CSS color string.
- bbox (dict; optional):
The bounding box coordinates of the item to label, in px relative
to the positioning parent of the Tooltip component.
`bbox` is a dict with keys:
- x0 (number; optional)
- y0 (number; optional)
- x1 (number; optional)
- y1 (number; optional)
- border_color (string; default '#d6d6d6'):
Color of the tooltip border, as a CSS color string.
- className (string; default ''):
The class of the tooltip.
- direction (a value equal to: 'top', 'right', 'bottom', 'left'; default 'right'):
The side of the `bbox` on which the tooltip should open.
- loading_text (string; default 'Loading...'):
The text displayed in the tooltip while loading.
- show (boolean; default True):
Whether to show the tooltip.
- targetable (boolean; default False):
Whether the tooltip itself can be targeted by pointer events. For
tooltips triggered by hover events, typically this should be left
`False` to avoid the tooltip interfering with those same events.
- zindex (number; default 1):
The `z-index` CSS property to assign to the tooltip. Components
with higher values will be displayed on top of components with
lower values."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Tooltip"
Bbox = TypedDict(
"Bbox",
{
"x0": NotRequired[NumberType],
"y0": NotRequired[NumberType],
"x1": NotRequired[NumberType],
"y1": NotRequired[NumberType],
},
)
def __init__(
self,
children: typing.Optional[ComponentType] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
className: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
bbox: typing.Optional["Bbox"] = None,
show: typing.Optional[bool] = None,
direction: typing.Optional[Literal["top", "right", "bottom", "left"]] = None,
border_color: typing.Optional[str] = None,
background_color: typing.Optional[str] = None,
loading_text: typing.Optional[str] = None,
zindex: typing.Optional[NumberType] = None,
targetable: typing.Optional[bool] = None,
**kwargs
):
self._prop_names = [
"children",
"id",
"background_color",
"bbox",
"border_color",
"className",
"direction",
"loading_text",
"show",
"style",
"targetable",
"zindex",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"children",
"id",
"background_color",
"bbox",
"border_color",
"className",
"direction",
"loading_text",
"show",
"style",
"targetable",
"zindex",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args if k != "children"}
super(Tooltip, self).__init__(children=children, **args)
setattr(Tooltip, "__init__", _explicitize_args(Tooltip.__init__))
@@ -0,0 +1,173 @@
# AUTO GENERATED FILE - DO NOT EDIT
import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
ComponentType = typing.Union[
str,
int,
float,
Component,
None,
typing.Sequence[typing.Union[str, int, float, Component, None]],
]
NumberType = typing.Union[
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]
class Upload(Component):
"""An Upload component.
Upload components allow your app to accept user-uploaded files via drag'n'drop
Keyword arguments:
- children (a list of or a singular dash component, string or number | string; optional):
Contents of the upload component.
- id (string; optional):
The ID of this component, used to identify dash components in
callbacks. The ID needs to be unique across all of the components
in an app.
- accept (string; optional):
Allow specific types of files. See
https://github.com/okonet/attr-accept for more information. Keep
in mind that mime type determination is not reliable across
platforms. CSV files, for example, are reported as text/plain
under macOS but as application/vnd.ms-excel under Windows. In some
cases there might not be a mime type set at all. See:
https://github.com/react-dropzone/react-dropzone/issues/276.
- className (string; optional):
HTML class name of the component.
- className_active (string; optional):
HTML class name of the component while active.
- className_disabled (string; optional):
HTML class name of the component if disabled.
- className_reject (string; optional):
HTML class name of the component if rejected.
- contents (string | list of strings; optional):
The contents of the uploaded file as a binary string.
- disable_click (boolean; default False):
Disallow clicking on the component to open the file dialog.
- disabled (boolean; default False):
Enable/disable the upload component entirely.
- filename (string | list of strings; optional):
The name of the file(s) that was(were) uploaded. Note that this
does not include the path of the file (for security reasons).
- last_modified (number | list of numbers; optional):
The last modified date of the file that was uploaded in unix time
(seconds since 1970).
- max_size (number; default -1):
Maximum file size in bytes. If `-1`, then infinite.
- min_size (number; default 0):
Minimum file size in bytes.
- multiple (boolean; default False):
Allow dropping multiple files.
- style_active (dict; default { borderStyle: 'solid', borderColor: '#6c6', backgroundColor: '#eee',}):
CSS styles to apply while active.
- style_disabled (dict; default { opacity: 0.5,}):
CSS styles if disabled.
- style_reject (dict; default { borderStyle: 'solid', borderColor: '#c66', backgroundColor: '#eee',}):
CSS styles if rejected."""
_children_props = []
_base_nodes = ["children"]
_namespace = "dash_core_components"
_type = "Upload"
def __init__(
self,
children: typing.Optional[ComponentType] = None,
id: typing.Optional[typing.Union[str, dict]] = None,
contents: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
filename: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
last_modified: typing.Optional[
typing.Union[NumberType, typing.Sequence[NumberType]]
] = None,
accept: typing.Optional[str] = None,
disabled: typing.Optional[bool] = None,
disable_click: typing.Optional[bool] = None,
max_size: typing.Optional[NumberType] = None,
min_size: typing.Optional[NumberType] = None,
multiple: typing.Optional[bool] = None,
className: typing.Optional[str] = None,
className_active: typing.Optional[str] = None,
className_reject: typing.Optional[str] = None,
className_disabled: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
style_active: typing.Optional[dict] = None,
style_reject: typing.Optional[dict] = None,
style_disabled: typing.Optional[dict] = None,
**kwargs
):
self._prop_names = [
"children",
"id",
"accept",
"className",
"className_active",
"className_disabled",
"className_reject",
"contents",
"disable_click",
"disabled",
"filename",
"last_modified",
"max_size",
"min_size",
"multiple",
"style",
"style_active",
"style_disabled",
"style_reject",
]
self._valid_wildcard_attributes = []
self.available_properties = [
"children",
"id",
"accept",
"className",
"className_active",
"className_disabled",
"className_reject",
"contents",
"disable_click",
"disabled",
"filename",
"last_modified",
"max_size",
"min_size",
"multiple",
"style",
"style_active",
"style_disabled",
"style_reject",
]
self.available_wildcard_properties = []
_explicit_args = kwargs.pop("_explicit_args")
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args if k != "children"}
super(Upload, self).__init__(children=children, **args)
setattr(Upload, "__init__", _explicitize_args(Upload.__init__))
@@ -0,0 +1,129 @@
import json
import os as _os
import sys as _sys
import dash as _dash
from ._imports_ import * # noqa: F401, F403, E402
from ._imports_ import __all__ as _components
from .express import ( # noqa: F401, E402
send_bytes,
send_data_frame,
send_file,
send_string,
)
__all__ = _components + [ # type: ignore[reportUnsupportedDunderAll]
"send_bytes",
"send_data_frame",
"send_file",
"send_string",
]
_basepath = _os.path.dirname(__file__)
_filepath = _os.path.abspath(_os.path.join(_basepath, "package-info.json"))
with open(_filepath) as f:
package = json.load(f)
package_name = package["name"].replace(" ", "_").replace("-", "_")
__version__ = package["version"]
# Module imports trigger a dash.development import, need to check this first
if not hasattr(_dash, "__plotly_dash") and not hasattr(_dash, "development"):
print(
"Dash was not successfully imported. Make sure you don't have a file "
"named \n'dash.py' in your current directory.",
file=_sys.stderr,
)
_sys.exit(1)
_current_path = _os.path.dirname(_os.path.abspath(__file__))
_this_module = "dash_core_components"
async_resources = [
"datepicker",
"dropdown",
"graph",
"highlight",
"markdown",
"mathjax",
"slider",
"upload",
]
_js_dist = []
_js_dist.extend(
[
{
"relative_package_path": "dcc/async-{}.js".format(async_resource),
"external_url": (
"https://unpkg.com/dash-core-components@{}"
"/dash_core_components/async-{}.js"
).format(__version__, async_resource),
"namespace": "dash",
"async": True,
}
for async_resource in async_resources
]
)
_js_dist.extend(
[
{
"relative_package_path": "dcc/async-{}.js.map".format(async_resource),
"external_url": (
"https://unpkg.com/dash-core-components@{}"
"/dash_core_components/async-{}.js.map"
).format(__version__, async_resource),
"namespace": "dash",
"dynamic": True,
}
for async_resource in async_resources
]
)
_js_dist.extend(
[
{
"relative_package_path": "dcc/{}.js".format(_this_module),
"external_url": (
"https://unpkg.com/dash-core-components@{}"
"/dash_core_components/dash_core_components.js"
).format(__version__),
"namespace": "dash",
},
{
"relative_package_path": "dcc/{}.js.map".format(_this_module),
"external_url": (
"https://unpkg.com/dash-core-components@{}"
"/dash_core_components/dash_core_components.js.map"
).format(__version__),
"namespace": "dash",
"dynamic": True,
},
{
"relative_package_path": "dcc/{}-shared.js".format(_this_module),
"external_url": (
"https://unpkg.com/dash-core-components@{}"
"/dash_core_components/dash_core_components-shared.js"
).format(__version__),
"namespace": "dash",
},
{
"relative_package_path": "dcc/{}-shared.js.map".format(_this_module),
"external_url": (
"https://unpkg.com/dash-core-components@{}"
"/dash_core_components/dash_core_components-shared.js.map"
).format(__version__),
"namespace": "dash",
"dynamic": True,
},
]
)
for _component in __all__:
setattr(locals()[_component], "_js_dist", _js_dist)
@@ -0,0 +1,53 @@
from .Checklist import Checklist
from .Clipboard import Clipboard
from .ConfirmDialog import ConfirmDialog
from .ConfirmDialogProvider import ConfirmDialogProvider
from .DatePickerRange import DatePickerRange
from .DatePickerSingle import DatePickerSingle
from .Download import Download
from .Dropdown import Dropdown
from .Geolocation import Geolocation
from .Graph import Graph
from .Input import Input
from .Interval import Interval
from .Link import Link
from .Loading import Loading
from .Location import Location
from .Markdown import Markdown
from .RadioItems import RadioItems
from .RangeSlider import RangeSlider
from .Slider import Slider
from .Store import Store
from .Tab import Tab
from .Tabs import Tabs
from .Textarea import Textarea
from .Tooltip import Tooltip
from .Upload import Upload
__all__ = [
"Checklist",
"Clipboard",
"ConfirmDialog",
"ConfirmDialogProvider",
"DatePickerRange",
"DatePickerSingle",
"Download",
"Dropdown",
"Geolocation",
"Graph",
"Input",
"Interval",
"Link",
"Loading",
"Location",
"Markdown",
"RadioItems",
"RangeSlider",
"Slider",
"Store",
"Tab",
"Tabs",
"Textarea",
"Tooltip",
"Upload",
]
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/react-select
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/
/*!
* repeat-string <https://github.com/jonschlinkert/repeat-string>
*
* Copyright (c) 2014-2015, Jon Schlinkert.
* Licensed under the MIT License.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* @license React
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,14 @@
/*!
Copyright (c) 2018 Jed Watson.
Licensed under the MIT License (MIT), see
http://jedwatson.github.io/classnames
*/
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,25 @@
/*!
* Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
*/
/*!
* The buffer module from node.js, for the browser.
*
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
* @license MIT
*/
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! moment.js
//! moment.js locale configuration
//! momentjs.com
//! version : 2.30.1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,106 @@
import io
import ntpath
import base64
# region Utils for Download component
def send_file(path, filename=None, type=None):
"""
Convert a file into the format expected by the Download component.
:param path: path to the file to be sent
:param filename: name of the file, if not provided the original filename is used
:param type: type of the file (optional, passed to Blob in the javascript layer)
:return: dict of file content (base64 encoded) and meta data used by the Download component
"""
# If filename is not set, read it from the path.
if filename is None:
filename = ntpath.basename(path)
# Read the file contents and send it.
with open(path, "rb") as f:
return send_bytes(f.read(), filename, type)
def send_bytes(src, filename, type=None, **kwargs):
"""
Convert data written to BytesIO into the format expected by the Download component.
:param src: array of bytes or a writer that can write to BytesIO
:param filename: the name of the file
:param type: type of the file (optional, passed to Blob in the javascript layer)
:return: dict of data frame content (base64 encoded) and meta data used by the Download component
"""
content = src if isinstance(src, bytes) else _io_to_str(io.BytesIO(), src, **kwargs)
return dict(
content=base64.b64encode(content).decode(),
filename=filename,
type=type,
base64=True,
)
def send_string(src, filename, type=None, **kwargs):
"""
Convert data written to StringIO into the format expected by the Download component.
:param src: a string or a writer that can write to StringIO
:param filename: the name of the file
:param type: type of the file (optional, passed to Blob in the javascript layer)
:return: dict of data frame content (NOT base64 encoded) and meta data used by the Download component
"""
content = src if isinstance(src, str) else _io_to_str(io.StringIO(), src, **kwargs)
return dict(content=content, filename=filename, type=type, base64=False)
def _io_to_str(data_io, writer, **kwargs):
# Some pandas writers try to close the IO, we do not want that.
data_io_close = data_io.close
data_io.close = lambda: None
# Write data content.
writer(data_io, **kwargs)
data_value = data_io.getvalue()
data_io_close()
return data_value
def send_data_frame(writer, filename, type=None, **kwargs):
"""
Convert data frame into the format expected by the Download component.
:param writer: a data frame writer
:param filename: the name of the file
:param type: type of the file (optional, passed to Blob in the javascript layer)
:return: dict of data frame content (base64 encoded) and meta data used by the Download component
Examples
--------
>>> df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [2, 1, 5, 6], 'c': ['x', 'x', 'y', 'y']})
...
>>> send_data_frame(df.to_csv, "mydf.csv") # download as csv
>>> send_data_frame(df.to_json, "mydf.json") # download as json
>>> send_data_frame(df.to_excel, "mydf.xls", index=False) # download as excel
>>> send_data_frame(df.to_pickle, "mydf.pkl") # download as pickle
"""
name = writer.__name__
# Check if the provided writer is known.
if name not in _data_frame_senders.keys():
raise ValueError(
"The provided writer ({}) is not supported, "
"try calling send_string or send_bytes directly.".format(name)
)
# Send data frame using the appropriate send function.
return _data_frame_senders[name](writer, filename, type, **kwargs)
_data_frame_senders = {
"to_csv": send_string,
"to_json": send_string,
"to_html": send_string,
"to_excel": send_bytes,
"to_feather": send_bytes,
"to_parquet": send_bytes,
"to_msgpack": send_bytes,
"to_stata": send_bytes,
"to_pickle": send_bytes,
}
# endregion

Some files were not shown because too many files have changed in this diff Show More