aboutsummaryrefslogtreecommitdiff
path: root/venv/lib/python3.8/site-packages/dash/_callback_context.py
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2025-07-31 17:27:24 -0400
committersotech117 <michael_foiani@brown.edu>2025-07-31 17:27:24 -0400
commit5bf22fc7e3c392c8bd44315ca2d06d7dca7d084e (patch)
tree8dacb0f195df1c0788d36dd0064f6bbaa3143ede /venv/lib/python3.8/site-packages/dash/_callback_context.py
parentb832d364da8c2efe09e3f75828caf73c50d01ce3 (diff)
add code for analysis of data
Diffstat (limited to 'venv/lib/python3.8/site-packages/dash/_callback_context.py')
-rw-r--r--venv/lib/python3.8/site-packages/dash/_callback_context.py323
1 files changed, 323 insertions, 0 deletions
diff --git a/venv/lib/python3.8/site-packages/dash/_callback_context.py b/venv/lib/python3.8/site-packages/dash/_callback_context.py
new file mode 100644
index 0000000..f64865c
--- /dev/null
+++ b/venv/lib/python3.8/site-packages/dash/_callback_context.py
@@ -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 it’s a pattern matching id, it will be a dict.
+ - “id_str”: (str) for pattern matching ids, it’s 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)