Skip to content

Commit 486f76a

Browse files
committed
merge dev
2 parents 0156d70 + daca40d commit 486f76a

File tree

13 files changed

+267
-88
lines changed

13 files changed

+267
-88
lines changed

.circleci/config.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,4 @@ workflows:
5757
version: 2
5858
build:
5959
jobs:
60-
- "test":
61-
context: dash-docker-hub
60+
- "test"

.github/workflows/CompatHelper.yml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
name: CompatHelper
2+
on:
3+
schedule:
4+
- cron: '00 00 * * *'
5+
workflow_dispatch:
6+
jobs:
7+
CompatHelper:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Pkg.add("CompatHelper")
11+
run: julia -e 'using Pkg; Pkg.add("CompatHelper")'
12+
- name: CompatHelper.main()
13+
env:
14+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
15+
run: julia -e 'using CompatHelper; CompatHelper.main()'

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ HTTP = "0.8.10"
3030
JSON = "0.21"
3131
JSON2 = "0.3"
3232
MD5 = "0.2"
33-
PlotlyBase = "0.3, 0.4"
33+
PlotlyBase = "0.3, 0.4, 0.5"
3434
julia = "1.2"
3535

3636
[extras]

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
## Project Status
88

9-
The core Dash component libraries have been submitted to the Julia package registry; upon their acceptance, `Dash.jl` will be submitted. The initial release of `Dash.jl` is anticipated in September 2020. A Julia version of the Dash Tutorial is currently in preparation, and will be available online soon. As of v1.15.0 of Dash, Julia components can be generated in tandem with Python and R components. Interested in getting involved with the project? Sponsorship is a great way to accelerate the progress of open source projects like this one; please feel free to [reach out to us](https://plotly.com/consulting-and-oem/)!
9+
As of v1.15.0 of Dash, Julia components can be generated in tandem with Python and R components. Interested in getting involved with the project? Sponsorship is a great way to accelerate the progress of open source projects like this one; please feel free to [reach out to us](https://plotly.com/consulting-and-oem/)! Just getting started? Check out the [Dash for Julia User Guide](https://dash-julia.plotly.com/)!
1010

1111
#### Create beautiful, analytic applications in Julia
1212

src/app/callbacks.jl

+27-16
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
dependency_id_string(id::NamedTuple) = sorted_json(id)
22
dependency_id_string(id::String) = sorted_json(id)
33

4-
function dependency_string(dep::Dependency{Trait, String}) where {Trait}
4+
function dependency_string(dep::Dependency{Trait, String}) where {Trait}
55
return "$(dep.id).$(dep.property)"
66
end
77

8-
function dependency_string(dep::Dependency{Trait, <:NamedTuple}) where {Trait}
8+
function dependency_string(dep::Dependency{Trait, <:NamedTuple}) where {Trait}
99
id_str = replace(
1010
sorted_json(dep.id),
1111
"."=>"\\."
@@ -33,7 +33,7 @@ end
3333
state::Union{Vector{State}, State} = []
3434
)
3535
36-
Create a callback that updates the output by calling function `func`.
36+
Create a callback that updates the output by calling function `func`.
3737
3838
# Examples
3939
@@ -59,9 +59,10 @@ function callback!(func::Union{Function, ClientsideFunction, String},
5959
app::DashApp,
6060
output::Union{Vector{<:Output}, Output},
6161
input::Union{Vector{<:Input}, Input},
62-
state::Union{Vector{<:State}, State} = State[]
62+
state::Union{Vector{<:State}, State} = State[];
63+
prevent_initial_call = nothing
6364
)
64-
return _callback!(func, app, CallbackDeps(output, input, state))
65+
return _callback!(func, app, CallbackDeps(output, input, state), prevent_initial_call = prevent_initial_call)
6566
end
6667

6768
"""
@@ -70,7 +71,7 @@ end
7071
deps...
7172
)
7273
73-
Create a callback that updates the output by calling function `func`.
74+
Create a callback that updates the output by calling function `func`.
7475
"Flat" version of `callback!` function, `deps` must be ``Output..., Input...[,State...]``
7576
7677
# Examples
@@ -85,7 +86,7 @@ app = dash() do
8586
8687
end
8788
end
88-
callback!(app,
89+
callback!(app,
8990
Output("outputID2", "children"),
9091
Output("outputID", "children"),
9192
Input("graphTitle", "value"),
@@ -97,13 +98,14 @@ end
9798
"""
9899
function callback!(func::Union{Function, ClientsideFunction, String},
99100
app::DashApp,
100-
deps::Dependency...
101+
deps::Dependency...;
102+
prevent_initial_call = nothing
101103
)
102104
output = Output[]
103105
input = Input[]
104106
state = State[]
105107
_process_callback_args(deps, (output, input, state))
106-
return _callback!(func, app, CallbackDeps(output, input, state, length(output) > 1))
108+
return _callback!(func, app, CallbackDeps(output, input, state, length(output) > 1), prevent_initial_call = prevent_initial_call)
107109
end
108110

109111
function _process_callback_args(args::Tuple{T, Vararg}, dest::Tuple{Vector{T}, Vararg}) where {T}
@@ -115,20 +117,29 @@ end
115117
function _process_callback_args(args::Tuple, dest::Tuple{Vector{T}, Vararg}) where {T}
116118
_process_callback_args(args, Base.tail(dest))
117119
end
118-
function _process_callback_args(args::Tuple, dest::Tuple{})
120+
function _process_callback_args(args::Tuple, dest::Tuple{})
119121
error("The callback method must received first all Outputs, then all Inputs, then all States")
120122
end
121-
function _process_callback_args(args::Tuple{}, dest::Tuple{})
123+
function _process_callback_args(args::Tuple{}, dest::Tuple{})
122124
end
123125

124126

125-
function _callback!(func::Union{Function, ClientsideFunction, String}, app::DashApp, deps::CallbackDeps)
126-
127+
function _callback!(func::Union{Function, ClientsideFunction, String}, app::DashApp, deps::CallbackDeps; prevent_initial_call)
128+
127129
check_callback(func, app, deps)
128-
130+
129131
out_symbol = Symbol(output_string(deps))
130-
callback_func = make_callback_func!(app, func, deps)
131-
push!(app.callbacks, out_symbol => Callback(callback_func, deps))
132+
callback_func = make_callback_func!(app, func, deps)
133+
push!(
134+
app.callbacks,
135+
out_symbol => Callback(
136+
callback_func,
137+
deps,
138+
isnothing(prevent_initial_call) ?
139+
get_setting(app, :prevent_initial_callbacks) :
140+
prevent_initial_call
141+
)
142+
)
132143
end
133144

134145

src/app/config.jl

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ struct DashConfig
66
routes_pathname_prefix ::String
77
assets_folder ::String
88
assets_url_path ::String
9-
assets_ignore ::String
9+
assets_ignore ::String
1010
serve_locally ::Bool
1111
suppress_callback_exceptions ::Bool
12+
prevent_initial_callbacks ::Bool
1213
eager_loading ::Bool
13-
meta_tags ::Vector{Dict{String, String}}
14+
meta_tags ::Vector{Dict{String, String}}
1415
assets_external_path ::Union{String, Nothing}
1516
include_assets_files ::Bool
1617
show_undo_redo ::Bool

src/app/dashapp.jl

+11
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,15 @@ If a parameter can be set by an environment variable, that is listed as:
265265
if your layout is dynamic, to bypass these checks.
266266
env: `DASH_SUPPRESS_CALLBACK_EXCEPTIONS`
267267
268+
- `prevent_initial_callbacks::Bool`: Default ``false``: Sets the default value
269+
of ``prevent_initial_call`` for all callbacks added to the app.
270+
Normally all callbacks are fired when the associated outputs are first
271+
added to the page. You can disable this for individual callbacks by
272+
setting ``prevent_initial_call`` in their definitions, or set it
273+
``true`` here in which case you must explicitly set it ``false`` for
274+
those callbacks you wish to have an initial call. This setting has no
275+
effect on triggering callbacks when their inputs change later on.
276+
268277
- `show_undo_redo::Bool`: Default ``false``, set to ``true`` to enable undo
269278
and redo buttons for stepping through the history of the app state.
270279
@@ -283,6 +292,7 @@ function dash(;
283292
assets_ignore = "",
284293
serve_locally = true,
285294
suppress_callback_exceptions = dash_env(Bool, "suppress_callback_exceptions", false),
295+
prevent_initial_callbacks = false,
286296
eager_loading = false,
287297
meta_tags = Dict{Symbol, String}[],
288298
index_string = default_index,
@@ -307,6 +317,7 @@ function dash(;
307317
assets_ignore,
308318
serve_locally,
309319
suppress_callback_exceptions,
320+
prevent_initial_callbacks,
310321
eager_loading,
311322
meta_tags,
312323
assets_external_path,

src/app/supporttypes.jl

+9-8
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ struct Dependency{Trait, IdT <: Union{String, NamedTuple}}
2222
end
2323

2424
dep_id_string(dep::Dependency{Trait, String}) where {Trait} = dep.id
25-
dep_id_string(dep::Dependency{Trait, <:NamedTuple}) where {Trait} = sorted_json(dep.id)
25+
dep_id_string(dep::Dependency{Trait, <:NamedTuple}) where {Trait} = sorted_json(dep.id)
2626

27-
dependency_tuple(dep::Dependency) = (id = dep_id_string(dep), property = dep.property)
27+
dependency_tuple(dep::Dependency) = (id = dep_id_string(dep), property = dep.property)
2828

2929
const Input = Dependency{TraitInput}
3030
const State = Dependency{TraitState}
@@ -37,7 +37,7 @@ We use "==" to denote two deps that refer to the same prop on
3737
the same component. In the case of wildcard deps, this means
3838
the same prop on *at least one* of the same components.
3939
"""
40-
function Base.:(==)(a::Dependency, b::Dependency)
40+
function Base.:(==)(a::Dependency, b::Dependency)
4141
(a.property == b.property) && is_id_matches(a, b)
4242
end
4343

@@ -59,7 +59,7 @@ end
5959
is_id_matches(a::Dependency{Trait1, String}, b::Dependency{Trait2, String}) where {Trait1, Trait2} = a.id == b.id
6060
is_id_matches(a::Dependency{Trait1, String}, b::Dependency{Trait2, <:NamedTuple}) where {Trait1, Trait2} = false
6161
is_id_matches(a::Dependency{Trait1, <:NamedTuple}, b::Dependency{Trait2, String}) where {Trait1, Trait2} = false
62-
function is_id_matches(a::Dependency{Trait1, <:NamedTuple}, b::Dependency{Trait2, <:NamedTuple}) where {Trait1, Trait2}
62+
function is_id_matches(a::Dependency{Trait1, <:NamedTuple}, b::Dependency{Trait2, <:NamedTuple}) where {Trait1, Trait2}
6363
(Set(keys(a.id)) != Set(keys(b.id))) && return false
6464

6565
for key in keys(a.id)
@@ -70,12 +70,12 @@ function is_id_matches(a::Dependency{Trait1, <:NamedTuple}, b::Dependency{Trait2
7070

7171
a_wild = is_wild(a_value)
7272
b_wild = is_wild(b_value)
73-
73+
7474
(!a_wild && !b_wild) && return false #Both not wild
75-
!(a_wild && b_wild) && continue #One wild, one not
75+
!(a_wild && b_wild) && continue #One wild, one not
7676
((a_value == ALL) || (b_value == ALL)) && continue #at least one is ALL
7777
((a_value == MATCH) || (b_value == MATCH)) && return false #one is MATCH and one is ALLSMALLER
78-
78+
7979
end
8080
return true
8181
end
@@ -100,6 +100,7 @@ end
100100
struct Callback
101101
func ::Union{Function, ClientsideFunction}
102102
dependencies ::CallbackDeps
103+
prevent_initial_call ::Bool
103104
end
104105

105106
is_multi_out(cb::Callback) = cb.dependencies.multi_out == true
@@ -108,7 +109,7 @@ get_output(cb::Callback, i) = cb.dependencies.output[i]
108109
first_output(cb::Callback) = first(cb.dependencies.output)
109110

110111
struct PreventUpdate <: Exception
111-
112+
112113
end
113114

114115

src/handler/state.jl

+7-5
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@ _dep_clientside_func(func::ClientsideFunction) = func
2323
_dep_clientside_func(func) = nothing
2424
function _dependencies_json(app::DashApp)
2525
result = map(values(app.callbacks)) do callback
26-
(inputs = dependency_tuple.(callback.dependencies.input),
27-
state = dependency_tuple.(callback.dependencies.state),
28-
output = output_string(callback.dependencies),
29-
clientside_function = _dep_clientside_func(callback.func)
26+
(
27+
inputs = dependency_tuple.(callback.dependencies.input),
28+
state = dependency_tuple.(callback.dependencies.state),
29+
output = output_string(callback.dependencies),
30+
clientside_function = _dep_clientside_func(callback.func),
31+
prevent_initial_call = callback.prevent_initial_call
3032
)
3133
end
3234
return JSON2.write(result)
@@ -52,7 +54,7 @@ make_reload_state(app::DashApp) = get_devsetting(app, :hot_reload) ? StateReload
5254
get_cache(state::HandlerState) = state.cache
5355

5456
function rebuild_cache!(state::HandlerState)
55-
cache = get_cache(state)
57+
cache = get_cache(state)
5658
(cache.resources, cache.index_string, cache.dependencies_json) = _cache_tuple(state.app, state.registry)
5759
cache.need_recache = false
5860
end

0 commit comments

Comments
 (0)