Skip to content

Commit 680423e

Browse files
Issue 481 - Support arbitrary file extensions in component suites (#1078)
1 parent 557f85e commit 680423e

File tree

8 files changed

+74
-11
lines changed

8 files changed

+74
-11
lines changed

@plotly/dash-generator-test-component-standard/base/__init__.py

+13
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,21 @@
1616
dict(
1717
relative_package_path='dash_generator_test_component_standard.js',
1818
namespace='dash_generator_test_component_standard'
19+
),
20+
dict(
21+
relative_package_path='godfather.ttf',
22+
namespace='dash_generator_test_component_standard',
23+
dynamic=True
24+
)
25+
]
26+
27+
_css_dist = [
28+
dict(
29+
relative_package_path='style.css',
30+
namespace='dash_generator_test_component_standard'
1931
)
2032
]
2133

2234
for _component in __all__:
2335
setattr(locals()[_component], '_js_dist', _js_dist)
36+
setattr(locals()[_component], '_css_dist', _css_dist)
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@font-face {
2+
font-family: 'godfather';
3+
src: url(./godfather.ttf) format('truetype');
4+
}

@plotly/dash-generator-test-component-standard/src/components/MyStandardComponent.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,19 @@ import React from 'react';
44
/**
55
* MyComponent description
66
*/
7-
const MyStandardComponent = ({ id, value }) => (<div id={id}>{value}</div>);
7+
const MyStandardComponent = ({ id, style, value }) => (<div id={id} style={style}>{value}</div>);
88

99
MyStandardComponent.propTypes = {
1010
/**
1111
* The id of the component
1212
*/
1313
id: PropTypes.string,
1414

15+
/**
16+
* The style
17+
*/
18+
style: PropTypes.shape,
19+
1520
/**
1621
* The value to display
1722
*/

CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55
## [UNRELEASED]
66
### Added
77
- [#1201](https://github.com/plotly/dash/pull/1201) New attribute `app.validation_layout` allows you to create a multi-page app without `suppress_callback_exceptions=True` or layout function tricks. Set this to a component layout containing the superset of all IDs on all pages in your app.
8+
- [#1078](https://github.com/plotly/dash/pull/1078) Permit usage of arbitrary file extensions for assets within component libraries
89

910
### Fixed
1011
- [#1201](https://github.com/plotly/dash/pull/1201) Fixes [#1193](https://github.com/plotly/dash/issues/1193) - prior to Dash 1.11, you could use `flask.has_request_context() == False` inside an `app.layout` function to provide a special layout containing all IDs for validation purposes in a multi-page app. Dash 1.11 broke this when we moved most of this validation into the renderer. This change makes it work again.
@@ -72,7 +73,7 @@ These functions are particularly useful for apps deployed on Dash Enterprise whe
7273

7374
### Changed
7475
- [#1035](https://github.com/plotly/dash/pull/1035) Simplify our build process.
75-
- [#1074](https://github.com/plotly/dash/pull/1045) Error messages when providing an incorrect property to a component have been improved: they now specify the component type, library, version, and ID (if available).
76+
- [#1074](https://github.com/plotly/dash/pull/1074) Error messages when providing an incorrect property to a component have been improved: they now specify the component type, library, version, and ID (if available).
7677

7778
### Fixed
7879
- [#1037](https://github.com/plotly/dash/pull/1037) Fix no_update test to allow copies, such as those stored and retrieved from a cache.

dash/dash.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import threading
1212
import re
1313
import logging
14+
import mimetypes
1415

1516
from functools import wraps
1617

@@ -45,6 +46,9 @@
4546
from . import _validate
4647
from . import _watch
4748

49+
# Add explicit mapping for map files
50+
mimetypes.add_type("application/json", ".map", True)
51+
4852
_default_index = """<!DOCTYPE html>
4953
<html>
5054
<head>
@@ -669,13 +673,8 @@ def serve_component_suites(self, package_name, fingerprinted_path):
669673

670674
_validate.validate_js_path(self.registered_paths, package_name, path_in_pkg)
671675

672-
mimetype = (
673-
{
674-
"js": "application/javascript",
675-
"css": "text/css",
676-
"map": "application/json",
677-
}
678-
)[path_in_pkg.split(".")[-1]]
676+
extension = "." + path_in_pkg.split(".")[-1]
677+
mimetype = mimetypes.types_map.get(extension, "application/octet-stream")
679678

680679
package = sys.modules[package_name]
681680
self.logger.debug(

dash/development/_r_components_generation.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ def write_js_metadata(pkg_data, project_shortname, has_wildcards):
505505
for filename in filenames:
506506
extension = os.path.splitext(filename)[1]
507507

508-
if extension not in [".css", ".js", ".map"]:
508+
if extension in [".py", ".pyc", ".json"]:
509509
continue
510510

511511
target_dirname = os.path.join(

tests/integration/test_generation.py

+42-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
from dash import Dash
2+
from dash.dependencies import Input, Output
3+
from dash.exceptions import PreventUpdate
4+
25
from dash_generator_test_component_nested import MyNestedComponent
36
from dash_generator_test_component_standard import MyStandardComponent
4-
from dash_html_components import Div
7+
from dash_html_components import Button, Div
8+
9+
from selenium.webdriver.support.ui import WebDriverWait
510

611

712
def test_gene001_simple_callback(dash_duo):
@@ -18,3 +23,39 @@ def test_gene001_simple_callback(dash_duo):
1823

1924
assert dash_duo.wait_for_element("#standard").text == "Standard"
2025
assert dash_duo.wait_for_element("#nested").text == "Nested"
26+
27+
dash_duo.percy_snapshot(name="gene001-simple-callback")
28+
29+
30+
def test_gene002_arbitrary_resources(dash_duo):
31+
app = Dash(__name__)
32+
33+
app.layout = Div([Button(id="btn"), Div(id="container")])
34+
35+
@app.callback(Output("container", "children"), [Input("btn", "n_clicks")])
36+
def update_container(n_clicks):
37+
if n_clicks is None:
38+
raise PreventUpdate
39+
40+
return MyStandardComponent(
41+
id="standard", value="Standard", style={"font-family": "godfather"}
42+
)
43+
44+
dash_duo.start_server(app)
45+
46+
assert (
47+
dash_duo.driver.execute_script("return document.fonts.check('1em godfather')")
48+
is False
49+
)
50+
51+
dash_duo.wait_for_element("#btn").click()
52+
assert dash_duo.wait_for_element("#standard").text == "Standard"
53+
54+
WebDriverWait(dash_duo.driver, 10).until(
55+
lambda _: dash_duo.driver.execute_script(
56+
"return document.fonts.check('1em godfather')"
57+
)
58+
is True,
59+
)
60+
61+
dash_duo.percy_snapshot(name="gene002-arbitrary-resource")

0 commit comments

Comments
 (0)