dash icon indicating copy to clipboard operation
dash copied to clipboard

expose NoUpdate

Open 2Ryan09 opened this issue 1 year ago • 5 comments

Expose NoUpdate at top-level dash.

The primary application is for type hinting, allowing for comprehensive type checking of dash callbacks.

See: #2799

Contributor Checklist

  • [X] Expose NoUpdate from dash._callback
  • [X] I have run the tests locally and they passed. (refer to testing section in contributing)
  • [X] I have added tests, or extended existing tests, to cover any new features or bugs fixed in this PR

2Ryan09 avatar Mar 16 '24 23:03 2Ryan09

I just pushed the minimal possible change in my mind: renaming NoUpdate to NoUpdateType and exposing it.

This does not implement the behavior @ndrezn mentions as it will still be of type dash._callback.NoUpdateType, but is there value in it being dash.NoUpdate? It's the only class as the other two imported into dash are functions, so maybe NoUpdate is just declared in the wrong module?

Given NoUpdate can be entirely described by {"_dash_no_update": "_dash_no_update"} (see context in #2800), can it not somehow inherit from Dict or TypedDict? This could make its behavior much more predictable and pythonic.

2Ryan09 avatar Mar 21 '24 02:03 2Ryan09

Given NoUpdate can be entirely described by {"_dash_no_update": "_dash_no_update"} (see context in #2800), can it not somehow inherit from Dict or TypedDict? This could make its behavior much more predictable and pythonic.

It does not equate to a typed dict, it's a singleton object, the dict representation is for internal use.

T4rk1n avatar Mar 21 '24 11:03 T4rk1n

In an attempt to keep the implementation of this PR at a minimum and, if I'm interpreting the conversation correctly up until now, is there any objection to the current state of this PR?

2Ryan09 avatar Apr 10 '24 07:04 2Ryan09

any lingering comments from you?

I'd rather we fix the cases where using NoUpdate would be creating an error instead of renaming the variable in hope it won't be used. I think the only case is actually just returning the class like this:

from dash import NoUpdate

def cb(...):
    return NoUpdate

intead of return NoUpdate()

Think we can add the check like this:

    @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"}
        )

Then change all our checks to NoUpdate.is_no_update(obj):

  • https://github.com/plotly/dash/blob/15e97b85d24461dfce907d038b7788db75d1f005/dash/_callback.py#L474
  • https://github.com/plotly/dash/blob/15e97b85d24461dfce907d038b7788db75d1f005/dash/_callback.py#L479

T4rk1n avatar Apr 11 '24 15:04 T4rk1n

any lingering comments from you?

I'd rather we fix the cases where using NoUpdate would be creating an error instead of renaming the variable in hope it won't be used. I think the only case is actually just returning the class like this:

from dash import NoUpdate

def cb(...):
    return NoUpdate

intead of return NoUpdate()

Think we can add the check like this:

    @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"}
        )

Then change all our checks to NoUpdate.is_no_update(obj):

  • https://github.com/plotly/dash/blob/15e97b85d24461dfce907d038b7788db75d1f005/dash/_callback.py#L474
  • https://github.com/plotly/dash/blob/15e97b85d24461dfce907d038b7788db75d1f005/dash/_callback.py#L479

I agree with this. Specifically, return NoUpdate seems like a more desirable behavior than return no_update.

However, such a change seems adjacent to the topic of this PR which is to simply expose the value. I am more than happy to open another PR suggesting this change.

2Ryan09 avatar Apr 11 '24 20:04 2Ryan09