Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attempt at bringing gen_resources back to life #208

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ docs/build
venv
*.pyc
tmp
gen_resources/build
gen_resources/build
dash-main
3 changes: 3 additions & 0 deletions .markdownlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ MD026: false

# MD032 Lists should be surrounded by blank lines
MD032: false

# MD033 Inline HTML
MD033: false
6 changes: 3 additions & 3 deletions Artifacts.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[dash_resources]
git-tree-sha1 = "c857e355d2c21dfc458fb315371431dda2506109"
git-tree-sha1 = "4b4e8cbd2109dbb0f653f4a74bcc533cd28a4e69"

[[dash_resources.download]]
sha256 = "4ff3910a8ff1f5420784397cfc6ad80341bbe03f1010eab38dcb9b8ce2423310"
url = "https://github.com/plotly/DashCoreResources/releases/download/v2.0.0+0/DashCoreResources.v2.0.0.tar.gz"
sha256 = "e3dd93831951d2b1047ed02a049c960b5e38c406a4650689e48d4d95ca4a7203"
url = "https://github.com/etpinard/DashCoreResources/releases/download/v2.10.2+1/DashCoreResources.v2.10.2.tar.gz"
1 change: 1 addition & 0 deletions gen_resources/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
LibGit2 = "76f85450-5226-5b5a-8eaa-529ad045b433"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
Expand Down
88 changes: 88 additions & 0 deletions gen_resources/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Generate Dash.jl artifacts

Dash.jl uses Julia
[Artifacts](https://docs.julialang.org/en/v1/stdlib/Artifacts/) to load
front-end resources that Dash.jl shares with the python version of
[dash](https://github.com/plotly/dash).

The [Artifacts.toml](../Artifacts.toml) file lists the location of the
publicly-available tarball containing all the required resources.

The tarballs are hosted on the
[DashCoreResources](https://github.com/plotly/DashCoreResources) repo, under
_Releases_. They are generated and deployed using the `generate.jl` script in
this directory.

## How to run `generate.jl` ?

### Step 0: get push rights to `DashCoreResources`

### Step 1: get GitHub personal access token

See [GitHub docs](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token)
for more info.

If using a fine-grained token, make sure to enable _Read and Write access to code_.

### Step 2: expose your token into your shell

```sh
# for example:
export GITHUB_TOKEN="<your GitHub personal access token>"
```

### Step 3: run `generate.jl`

```sh
cd Dash.jl/gen_resources

# install `generate.jl` deps
julia --project -e 'import Pkg; Pkg.instantiate()'

# generate `gen_resources/build/deploy/` content,
# but do not deploy!
julia --project generate.jl

# if everything looks fine,
# generate `gen_resources/build/deploy/` content (again) and
# deploy to the `DashCoreResource` releases with:
julia --project generate.jl --deploy
```

#### If `generate.jl` errors

<details>
<summary>with a PyError / PyImport error</summary>

that is an error like:

```sh
ERROR: LoadError: PyError (PyImport_ImportModule

The Python package dash could not be imported by pyimport. Usually this means
that you did not install dash in the Python version being used by PyCall.

PyCall is currently configured to use the Python version at:

/usr/bin/python3
```

try

```jl
using PyCall
ENV["PYTHON"] = joinpath(homedir(), ".julia/conda/3/x86_64/bin")
import Pkg
Pkg.build("PyCall")
# check that it matches with
PyCall.pyprogramname
```

and then re-run `generate.jl`.

</details>

### Step 4: Commit the changes to `Artifacts.toml`

and push to [plotly/Dash.jl](https://github.com/plotly/Dash.jl)
(preferably on a new branch) to get a CI test run started.
6 changes: 3 additions & 3 deletions gen_resources/Sources.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
[deploy]
repo = "plotly/DashCoreResources"
repo = "etpinard/DashCoreResources"
[dash]
url = "https://github.com/plotly/dash.git"
tag = "v2.0.0"
tag = "v2.10.2"
[dash_renderer]
module = "dash_renderer"
module = "dash._dash_renderer"
resources_path = "."
[components]
[components.dash_html_components]
Expand Down
2 changes: 1 addition & 1 deletion gen_resources/generate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ build_dir = joinpath(@__DIR__, "build")

artifact_file = joinpath(@__DIR__, "..", "Artifacts.toml")

generate(ARGS, sources, build_dir, artifact_file)
generate(ARGS, sources, build_dir, artifact_file)
2 changes: 1 addition & 1 deletion gen_resources/generator/components.jl
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,4 @@ function arg_docstring(prop_name, type_object, required, description, indent_num
")",
isempty(description) ? "" : string(": ", description)
)
end
end
4 changes: 2 additions & 2 deletions gen_resources/generator/dash.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
install_dash(url, tag)

Clone python dash into `dash` folder and install (reinstall) it to current python enviroment
Clone python dash into `dash` folder and install (reinstall) it to current python environment
"""
function install_dash(url, tag)
Conda.pip_interop(true)
Expand Down Expand Up @@ -157,4 +157,4 @@ function components_module_resources(module_name; name, prefix, metadata_file)
)

return meta
end
end
2 changes: 1 addition & 1 deletion gen_resources/generator/deploy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,4 @@ function upload_to_releases(repo_name, tag, tarball_path; attempts = 3)
end
end
error("Unable to upload $(tarball_path) to GitHub repo $(repo_name) on tag $(tag)")
end
end
2 changes: 1 addition & 1 deletion gen_resources/generator/generator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ function generate(ARGS, sources, build_dir, artifact_file)
end
@info "resource generation done!"

end
end
4 changes: 2 additions & 2 deletions gen_resources/generator/github.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const _github_auth = Ref{GitHub.Authorization}()
function github_auth(;allow_anonymous::Bool=true)
if !isassigned(_github_auth) || !allow_anonymous && isa(_github_auth[], GitHub.AnonymousAuth)
# If the user is feeding us a GITHUB_TOKEN token, use it!
if length(get(ENV, "GITHUB_TOKEN", "")) == 40
if length(get(ENV, "GITHUB_TOKEN", "")) >= 40
_github_auth[] = GitHub.authenticate(ENV["GITHUB_TOKEN"])
else
if allow_anonymous
Expand Down Expand Up @@ -112,4 +112,4 @@ function obtain_token(; outs=stdout, github_api=GitHub.DEFAULT_API)

return token
end
end
end
2 changes: 1 addition & 1 deletion gen_resources/generator/gitutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ function with_gitcreds(f, username::AbstractString, password::AbstractString)
finally
Base.shred!(creds)
end
end
end
34 changes: 15 additions & 19 deletions src/init/resources.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,33 +23,28 @@ dash_module_resource(meta) = Resource(
async = haskey(meta, "async") ? string(meta["async"]) : nothing
)

dash_module_resource_pkg(meta; resource_path, version) = ResourcePkg(
meta["namespace"],
resource_path, version = version,
dash_module_resource.(meta["resources"])
)

function setup_renderer_resources()
renderer_meta = _metadata.dash_renderer
renderer_resource_path = joinpath(artifact"dash_resources", "dash_renderer_deps")
renderer_version = renderer_meta["version"]
DashBase.main_registry().dash_dependency = (
dev = ResourcePkg(
"dash_renderer",
renderer_resource_path, version = renderer_meta["version"],
renderer_resource_path, version = renderer_version,
dash_dependency_resource.(renderer_meta["js_dist_dependencies"]["dev"])
),
prod = ResourcePkg(
"dash_renderer",
renderer_resource_path, version = renderer_meta["version"],
renderer_resource_path, version = renderer_version,
dash_dependency_resource.(renderer_meta["js_dist_dependencies"]["prod"])
)
)

DashBase.main_registry().dash_renderer = dash_module_resource_pkg(
renderer_meta["deps"][1],
resource_path = renderer_resource_path,
version = renderer_meta["version"]
)
renderer_renderer_meta = renderer_meta["deps"][1]
DashBase.main_registry().dash_renderer = ResourcePkg(
"dash_renderer",
renderer_resource_path, version = renderer_version,
dash_module_resource.(renderer_renderer_meta["resources"])
)
end

function load_all_metadata()
Expand All @@ -72,11 +67,12 @@ function setup_dash_resources()
version = meta["version"]
for dep in meta["deps"]
DashBase.register_package(
dash_module_resource_pkg(
dep,
resource_path = path,
version = version
ResourcePkg(
dep["namespace"],
path,
version = version,
dash_module_resource.(dep["resources"])
)
)
end
end
end
38 changes: 38 additions & 0 deletions test/integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Dash.jl integration tests

## How to run the integration tests locally inside the `dashjl-tests` container

```sh
# grab a copy of the python (main) dash repo
git clone --depth 1 https://github.com/plotly/dash.git -b dev dash-main

# start `dashjl-tests`
docker run -t -d --name dashjl-tests -v .:/home/circleci/project etpinard/dashjl-tests:0.3.0
# ssh into it as root (some python deps need that)
docker exec -u 0 -it dashjl-tests bash

# [on 1st session] install pip deps
cd /home/circleci/project/dash-main
pip install --upgrade pip wheel
pip install -e .[ci,dev,testing] --progress-bar off

# [on 1st session] install chrome
cd /home/circleci
wget https://raw.githubusercontent.com/CircleCI-Public/browser-tools-orb/main/src/scripts/install-chrome.sh
chmod +x install-chrome.sh
ORB_PARAM_CHANNEL="stable" ORB_PARAM_CHROME_VERSION="latest" ./install-chrome.sh

# [on 1st session] install chromedriver
wget https://raw.githubusercontent.com/CircleCI-Public/browser-tools-orb/main/src/scripts/install-chromedriver.sh
chmod +x ./install-chromedriver.sh
ORB_PARAM_DRIVER_INSTALL_DIR=/usr/local/bin/ ./install-chromedriver.sh

# [on 1st session] instantiate julia deps
cd /home/circleci/project/
julia --project -e 'import Pkg; Pkg.instantiate()'

# update julia deps then run integration tests
cd /home/circleci/project/
julia --project -e 'import Pkg; Pkg.update()'
pytest --headless --nopercyfinalize --percy-assets=test/assets/ test/integration/
```
6 changes: 3 additions & 3 deletions test/integration/clientside/test_clientside.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ def test_jlclsd004_clientside_multiple_outputs(dashjl):
]:
dashjl.wait_for_text_to_equal(selector, expected, timeout=10)

def test_jlclsd005_clientside_fails_when_returning_a_promise(dashjl):
def test_jlclsd005_clientside_when_returning_a_promise(dashjl):
fp = jl_test_file_path("jlclsd005_clientside_fails_when_returning_a_promise.jl")
dashjl.start_server(fp)

dashjl.wait_for_text_to_equal("#input", "hello", timeout=10)
dashjl.wait_for_text_to_equal("#side-effect", "side effect")
dashjl.wait_for_text_to_equal("#output", "output")
dashjl.wait_for_text_to_equal("#output", "foo")

def test_jlclsd006_PreventUpdate(dashjl):
fp = jl_test_file_path("jlclsd006_PreventUpdate.jl")
Expand Down Expand Up @@ -151,4 +151,4 @@ def test_jlclsd008_clientside_inline_source(dashjl):

dashjl.find_element("#input").send_keys("hello world")
dashjl.wait_for_text_to_equal("#output-serverside", 'Server says "hello world"', timeout=10)
dashjl.wait_for_text_to_equal("#output-clientside", 'Client says "hello world"')
dashjl.wait_for_text_to_equal("#output-clientside", 'Client says "hello world"')
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ test_cases = Dict(
"component"=> dcc_checklist,
"props"=> (options = [Dict("label" => "hello")], value = ["test"]),
),
"invalid-nested-prop"=> Dict(
"fail"=> true,
"name"=> "invalid nested prop",
"component"=> dcc_checklist,
"props"=> (options = [Dict("label"=> "hello", "value"=> true)], value = ["test"]),
),
"invalid-arrayOf"=> Dict(
"fail"=> true,
"name"=> "invalid arrayOf",
Expand Down Expand Up @@ -73,6 +67,12 @@ test_cases = Dict(
"component"=> html_div,
"props"=> (children = Dict("hello" => "world"),),
),
"allow-nested-prop"=> Dict(
"fail"=> false,
"name"=> "allow nested prop",
"component"=> dcc_checklist,
"props"=> (options = [Dict("label"=> "hello", "value"=> true)], value = ["test"]),
),
"allow-null-2"=> Dict(
"fail"=> false,
"name"=> "allow null as value",
Expand Down
13 changes: 7 additions & 6 deletions test/integration/devtools/test_props_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ def jl_test_file_path(filename):
"fail": True,
"name": 'missing required "value" inside options',
},
"invalid-nested-prop": {
"fail": True,
"name": "invalid nested prop",
},
"invalid-arrayOf": {
"fail": True,
"name": "invalid arrayOf",
Expand Down Expand Up @@ -56,6 +52,10 @@ def jl_test_file_path(filename):
"fail": True,
"name": "returning a dictionary",
},
"allow-nested-prop": {
"fail": False,
"name": "allow nested prop",
},
"allow-null-2": {
"fail": False,
"name": "allow null as value",
Expand Down Expand Up @@ -99,6 +99,7 @@ def test_jldvpc001_prop_check_errors_with_path(dashjl):

if test_cases[tc]["fail"]:
dashjl.wait_for_element(".test-devtools-error-toggle", timeout=10).click()
dashjl.wait_for_element(".dash-error-card")
dashjl.wait_for_element(".dash-fe-error__info")
else:
dashjl.wait_for_element("#new-component", timeout=2)
dashjl.wait_for_element("#new-component", timeout=2)
dashjl.wait_for_no_elements(".test-devtools-error-toggle")