Skip to content

Commit 0017806

Browse files
authored
Merge branch 'dev' into DataTable-whitespace-fix
2 parents bab36c9 + eef8f1c commit 0017806

File tree

16 files changed

+251
-93
lines changed

16 files changed

+251
-93
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version: 2.1
33
orbs:
44
win: circleci/[email protected]
55
percy: percy/[email protected]
6-
browser-tools: circleci/[email protected].6
6+
browser-tools: circleci/[email protected].8
77

88

99
jobs:

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# These owners will be the default owners for everything in
22
# the repo. Unless a later match takes precedence
3-
* @alexcjohnson @T4rk1n @ndrezn
3+
* @alexcjohnson @T4rk1n @ndrezn @gvwilson @emilykl

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).
77
## Added
88

99
- [#2881](https://github.com/plotly/dash/pull/2881) Add outputs_list to window.dash_clientside.callback_context. Fixes [#2877](https://github.com/plotly/dash/issues/2877).
10+
- [#2903](https://github.com/plotly/dash/pull/2903) Add callback on_error handler, either globally on Dash init or per callback basis. Receives the exception as first argument, can return output(s) or None for `no_update`. Access to original callback context is preserved and `set_props` works inside the error handler.
11+
- [#2936](https://github.com/plotly/dash/pull/2936) Adds support for TypeScript 5.5+.
12+
- [#2789](https://github.com/plotly/dash/pull/2789) Add library loading capacity to `_allow_dynamic_callbacks`
1013

1114
## Fixed
1215

@@ -15,6 +18,10 @@ This project adheres to [Semantic Versioning](https://semver.org/).
1518
- [#2896](https://github.com/plotly/dash/pull/2896) The tabIndex parameter of Div can accept number or string type. Fixes [#2891](https://github.com/plotly/dash/issues/2891)
1619
- [#2900](https://github.com/plotly/dash/pull/2900) Allow strings in layout list. Fixes [#2890](https://github.com/plotly/dash/issues/2890)
1720
- [#2908](https://github.com/plotly/dash/pull/2908) Fix when environment variables are ignored by Dash.run() at runtime. Fixes [#2902](https://github.com/plotly/dash/issues/2902)
21+
- [#2888](https://github.com/plotly/dash/pull/2888) Add id to dcc.Loading DOM. Fixes [#2878](https://github.com/plotly/dash/issues/2878)
22+
- [#2922](https://github.com/plotly/dash/pull/2922) Fix background callback hash_function when source is unavailable. Fixes [#1885](https://github.com/plotly/dash/issues/1885)
23+
- [#2915](https://github.com/plotly/dash/pull/2915) Fix 'AttributeError' when layout is a function that returns a list of components. Fixes [#2905](https://github.com/plotly/dash/issues/2905)
24+
- [#2956](https://github.com/plotly/dash/pull/2956) Add missing useEffect dependency to dcc.Loading component.
1825

1926
## [2.17.1] - 2024-06-12
2027

@@ -41,6 +48,7 @@ This project adheres to [Semantic Versioning](https://semver.org/).
4148
- `target_components` specifies components/props triggering the loading spinner
4249
- `custom_spinner` enables using a custom component for loading messages instead of built-in spinners
4350
- `display` overrides the loading status with options for "show," "hide," or "auto"
51+
4452
- [#2822](https://github.com/plotly/dash/pull/2822) Support no output callbacks. Fixes [#1549](https://github.com/plotly/dash/issues/1549)
4553
- [#2822](https://github.com/plotly/dash/pull/2822) Add global set_props. Fixes [#2803](https://github.com/plotly/dash/issues/2803)
4654

CONTRIBUTING.md

Lines changed: 120 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,136 @@
11
# Contributor Guide
22

33
## Getting Started
4+
Glad that you decided to make your contribution in Dash. This guide provides instructions to set up and build the Dash repository and describes best practices when contributing to the Dash repository.
45

5-
Glad that you decided to make your contribution in Dash, to set up your development environment, run the following commands:
6+
### Fork the Dash repository
7+
When contributing to the Dash repository you should always work in your own copy of the Dash repository. Create a fork of the `dev`-branch, to create a copy of the Dash repository in your own GitHub account. See official instructions for [creating a fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) if needed.
68

9+
Clone the forked repository (either option will work). Replace `<your_user_name>` with your user name.
10+
```
11+
git clone https://github.com/<your_user_name>/dash.git
12+
```
13+
or
14+
```
15+
git clone [email protected]:<your_user_name>/dash.git
16+
```
17+
18+
When working on a new feature, always create a new branch and create the feature in that branch. For more best practices, read the [Git section](#git).
19+
20+
### Configuring your system
21+
22+
<details>
23+
<summary>For JavaScript beginners: What are nvm, npm and Node?</summary>
24+
25+
If you are new to JavaScript, many aspects of setting up a working environment and working with the new ecosystem can be a bit overwhelming. Especially if Plotly Dash is your first experience with the JavaScript ecosystem. This section explains common terms that are used when working with JavaScript environments: `nvm`, `Node`, and `npm`
26+
- `nvm` stands for Node Version Manager. This is a tool that allows you to manage Node installations. Quite convenient if you are working on multiple tools that require different versions of Node.js. `nvm` allows you to switch between Node installations with a single command.
27+
- `Node.js` is the actual JavaScript runtime environment. Visit the [official site](https://nodejs.org/en) for more info. Don't download Node just yet, install it through `nvm`.
28+
- `npm` stands for Node Package Manager. This is the largest software registry for JavaScript packages. Check the [official site](https://docs.npmjs.com/about-npm) for more info.
29+
30+
---
31+
</details>
32+
33+
<details>
34+
35+
<summary>Installing JavaScript on your system</summary>
36+
37+
> **For Windows users**: `nvm` is not integrated in Windows so a third-party tool needs to be used. If you don't have one yet, you can start with [NVM for Windows](https://github.com/coreybutler/nvm-windows) (`nvm-windows`). This version manager is widely used and is well recommended.
38+
>
39+
> Carefully follow the installation instructions listed on the GitHub page. As recommended by the installation instructions there: uninstall any pre-existsing Node installations. You will run into permission errors otherwise.
40+
41+
With `nvm` available from the command line open any terminal of your preference and install Node and npm:
42+
```
43+
nvm install latest
44+
```
45+
After installation is complete, activate the Node environment (**admin access required**)
46+
```
47+
nvm use latest
48+
```
49+
Confirm that the activation was successfull
50+
```
51+
node -v
52+
npm -v
53+
```
54+
If these commands are not recognized, close the terminal, re-open a new instance and retry. If the commands return a version number, you have set up your JavaScript environment successfully!
55+
56+
---
57+
</details>
58+
59+
## Building Dash
60+
### For Windows users: use a Bash terminal
61+
The scripts that run during the build process are designed for a Bash terminal. The default terminals on Windows systems are either PowerShell or Command Prompt. However, the build process will fail (potentially bricking your Node environment) when using these terminals.
62+
63+
The listed commands should be executed from a Bash terminal, e.g. you can use the Git Bash terminal (which is normally installed when installing Git using the default settings). Otherwise, you need to find another way to access a Bash terminal.
64+
65+
### Build process
66+
The build process is mostly the same for Windows and Linux systems. Wherever there are differences between the operating systems, it is marked.
67+
68+
<details>
69+
<summary> Pycharm automatically loads Python environments! </summary>
70+
71+
If you work in Pycharm you can open the Dash repo directory as a project (`File -> Open` then browse for the `dash` directory containing your dash repo, and open the directory as a project). You can configure your Python virtual environment using the Python Interpreter tool.
72+
73+
Secondly, you can open the Git Bash terminal in Pycharm and it will automatically activate your selected Python Interpreter in the terminal. You can verify this by executing `pip --version` in the Git Bash terminal, it will show you the path from where pip is run, which is the path where your virtual environment is installed. If you follow these steps, you can skip the first few steps in the overview below.
74+
75+
---
76+
</details>
77+
78+
Open a Bash terminal in the `dash` repository, Git Bash terminal for example on Windows. Create and activate virtual environment (skip this part if you manage the Python Interpreter via Pycharm):
79+
- Linux/Mac:
80+
81+
On some Linux/Mac environments, use `.` instead of `source`
82+
```bash
83+
$ python3 -m venv .venv/dev
84+
$ source .venv/dev/bin/activate
85+
```
86+
- Windows:
87+
```bash
88+
$ python -m venv .venv/dev
89+
$ source .venv/dev/scripts/activate
90+
```
91+
92+
Install dash and dependencies:
793
```bash
8-
# in your working directory
9-
$ git clone [email protected]:plotly/dash.git
10-
$ cd dash
11-
$ python3 -m venv .venv/dev
12-
# activate the virtualenv
13-
# on windows `.venv\dev\scripts\activate`
14-
# on some linux / mac environments, use `.` instead of `source`
15-
$ source .venv/dev/bin/activate
16-
# install dash and dependencies
1794
$ pip install -e .[ci,dev,testing,celery,diskcache] # in some shells you need \ to escape []
1895
$ npm ci
19-
# this script will build the dash-core-components, dash-html-components, dash-table,
20-
# and renderer bundles; this will build all bundles from source code in their
21-
# respective directories. The only true source of npm version is defined
22-
# in package.json for each package.
23-
#
24-
$ npm run build # runs `renderer build` and `npm build` in dcc, html, table
25-
# build and install components used in tests
26-
# on windows, the developer will need to use `npm run first-build` this performs additional first steps
27-
#
28-
# Alternatively one could run part of the build process e.g.
96+
```
97+
`npm ci` does a clean install of all packages listed in package-lock.json. Package versions will be exactly like stated in the file.
98+
99+
Next, build dash-core-components, dash-html-components, dash-table, and renderer bundles. This will build all bundles from source code in their respective directories. The only true source of npm version is defined in package.json for each package:
100+
- Linux/Mac:
101+
```bash
102+
$ npm run build # runs `renderer build` and `npm build` in dcc, html, table
103+
```
104+
105+
- Windows:
106+
107+
On Windows the build is done via the first-build script. This adds extra steps that are automatically applied on Linux systems, but not on Windows systems:
108+
```bash
109+
$ npm run first-build
110+
```
111+
112+
When you first clone the repository, and check out a new branch, you must run the full build as above. Later on, when you only work in one part of the library, you could run part of the build process e.g.
113+
```bash
29114
$ dash-update-components "dash-core-components"
30-
# to only build dcc when developing dcc
31-
# But when you first clone check out a new branch, you must run the full build as above.
32-
#
115+
116+
```
117+
to only build dcc when developing dcc.
118+
119+
Build and install components used in tests:
120+
```bash
33121
$ npm run setup-tests.py # or npm run setup-tests.R
34-
# you should see dash points to a local source repo
122+
```
123+
124+
Finally, check that the installation succeeded by checking the output of this command:
125+
```bash
35126
$ pip list | grep dash
36127
```
37128

129+
The output should look like this:
130+
```bash
131+
dash <version number> /path/to/local/dash/repo/
132+
```
133+
38134
### Dash-Renderer Beginner Guide
39135

40136
`Dash Renderer` began as a separate repository. It was merged into the main `Dash` repository as part of the 1.0 release. It is the common frontend for all Dash backends (**R** and **Python**), and manages React Component layout and backend event handling.

components/dash-core-components/src/components/Loading.react.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ const Loading = ({
122122
}
123123
}
124124
}
125-
}, [delay_hide, delay_show, loading_state, display]);
125+
}, [delay_hide, delay_show, loading_state, display, showSpinner]);
126126

127127
const Spinner = showSpinner && getSpinner(spinnerType);
128128

dash/_callback.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
handle_grouped_callback_args,
1111
Output,
1212
)
13+
from .development.base_component import ComponentRegistry
1314
from .exceptions import (
1415
InvalidCallbackReturnValue,
1516
PreventUpdate,
1617
WildcardInLongCallback,
1718
MissingLongCallbackManagerError,
1819
LongCallbackError,
20+
ImportedInsideCallbackError,
1921
)
2022

2123
from ._grouping import (
@@ -354,11 +356,14 @@ def wrap_func(func):
354356
def add_context(*args, **kwargs):
355357
output_spec = kwargs.pop("outputs_list")
356358
app_callback_manager = kwargs.pop("long_callback_manager", None)
359+
357360
callback_ctx = kwargs.pop(
358361
"callback_context", AttributeDict({"updated_props": {}})
359362
)
363+
app = kwargs.pop("app", None)
360364
callback_manager = long and long.get("manager", app_callback_manager)
361365
error_handler = on_error or kwargs.pop("app_on_error", None)
366+
original_packages = set(ComponentRegistry.registry)
362367

363368
if has_output:
364369
_validate.validate_output_spec(insert_output, output_spec, Output)
@@ -507,7 +512,7 @@ def add_context(*args, **kwargs):
507512
if not multi:
508513
output_value = NoUpdate()
509514
else:
510-
output_value = [NoUpdate for _ in output_spec]
515+
output_value = [NoUpdate() for _ in output_spec]
511516
else:
512517
raise err
513518

@@ -557,6 +562,18 @@ def add_context(*args, **kwargs):
557562

558563
response["response"] = component_ids
559564

565+
if len(ComponentRegistry.registry) != len(original_packages):
566+
diff_packages = list(
567+
set(ComponentRegistry.registry).difference(original_packages)
568+
)
569+
if not allow_dynamic_callbacks:
570+
raise ImportedInsideCallbackError(
571+
f"Component librar{'y' if len(diff_packages) == 1 else 'ies'} was imported during callback.\n"
572+
"You can set `_allow_dynamic_callbacks` to allow for development purpose only."
573+
)
574+
dist = app.get_dist(diff_packages)
575+
response["dist"] = dist
576+
560577
try:
561578
jsonResponse = to_json(response)
562579
except TypeError:

dash/dash-renderer/src/actions/callbacks.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ import {handlePatch, isPatch} from './patch';
4545
import {getPath} from './paths';
4646

4747
import {requestDependencies} from './requestDependencies';
48+
49+
import {loadLibrary} from '../utils/libraries';
50+
4851
import {parsePMCId} from './patternMatching';
4952
import {replacePMC} from './patternMatching';
5053

@@ -576,8 +579,15 @@ function handleServerside(
576579
}
577580

578581
if (!long || data.response !== undefined) {
579-
completeJob();
580-
finishLine(data);
582+
if (data.dist) {
583+
Promise.all(data.dist.map(loadLibrary)).then(() => {
584+
completeJob();
585+
finishLine(data);
586+
});
587+
} else {
588+
completeJob();
589+
finishLine(data);
590+
}
581591
} else {
582592
// Poll chain.
583593
setTimeout(

dash/dash-renderer/src/types/callbacks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export type CallbackResponseData = {
105105
running?: CallbackResponse;
106106
runningOff?: CallbackResponse;
107107
cancel?: ICallbackProperty[];
108+
dist?: any;
108109
sideUpdate?: any;
109110
};
110111

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
type LibraryResource = {
2+
type: '_js_dist' | '_css_dist';
3+
url: string;
4+
};
5+
6+
export function loadLibrary(resource: LibraryResource) {
7+
let prom;
8+
const head = document.querySelector('head');
9+
if (resource.type === '_js_dist') {
10+
const element = document.createElement('script');
11+
element.src = resource.url;
12+
element.async = true;
13+
prom = new Promise<void>((resolve, reject) => {
14+
element.onload = () => {
15+
resolve();
16+
};
17+
element.onerror = error => reject(error);
18+
});
19+
20+
head?.appendChild(element);
21+
} else if (resource.type === '_css_dist') {
22+
const element = document.createElement('link');
23+
element.href = resource.url;
24+
element.rel = 'stylesheet';
25+
prom = new Promise<void>((resolve, reject) => {
26+
element.onload = () => {
27+
resolve();
28+
};
29+
element.onerror = error => reject(error);
30+
});
31+
head?.appendChild(element);
32+
}
33+
return prom;
34+
}

0 commit comments

Comments
 (0)