Skip to content

Commit b5437d3

Browse files
authored
Merge branch 'dev' into create-pull-request/patch
2 parents 0fe733a + 8ade05e commit b5437d3

86 files changed

Lines changed: 9370 additions & 631 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.ai/ARCHITECTURE.md

Lines changed: 317 additions & 6 deletions
Large diffs are not rendered by default.

.ai/COMMANDS.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ pip install -e .[ci,dev,testing,celery,diskcache]
1414
npm ci
1515
```
1616

17+
### Optional Backend Dependencies
18+
19+
```bash
20+
# For Quart backend (ASGI async)
21+
pip install dash[quart]
22+
23+
# For FastAPI backend (ASGI async)
24+
pip install dash[fastapi]
25+
26+
# For async callbacks with Flask
27+
pip install dash[async]
28+
```
29+
1730
## Building
1831

1932
```bash
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
name: Post Test Status
2+
3+
# This workflow runs in the base repo context (with write permissions)
4+
# even for fork PRs, allowing us to post commit statuses and check runs.
5+
#
6+
# Add any status posting or check run creation for fork PRs here to avoid
7+
# "Resource not accessible by integration" errors.
8+
9+
on:
10+
workflow_run:
11+
workflows: ["Dash Testing"]
12+
types:
13+
- completed
14+
15+
jobs:
16+
post-skipped-statuses:
17+
name: Post Statuses for Skipped Jobs
18+
runs-on: ubuntu-latest
19+
if: github.event.workflow_run.event == 'pull_request'
20+
permissions:
21+
statuses: write
22+
actions: read
23+
steps:
24+
- name: Post statuses for skipped jobs
25+
uses: actions/github-script@v7
26+
with:
27+
script: |
28+
const { owner, repo } = context.repo;
29+
const runId = context.payload.workflow_run.id;
30+
const headSha = context.payload.workflow_run.head_sha;
31+
32+
// Define jobs that need a success status posted when skipped
33+
const skippedStatusJobs = [
34+
{
35+
jobName: 'Dash Table Visual Tests',
36+
statusContext: 'percy/dash-table-test',
37+
description: 'Skipped — no dash-table changes'
38+
}
39+
// Add more jobs here as needed
40+
];
41+
42+
// Get all jobs for the workflow run
43+
const { data: { jobs } } = await github.rest.actions.listJobsForWorkflowRun({
44+
owner,
45+
repo,
46+
run_id: runId,
47+
});
48+
49+
// Post status for each skipped job
50+
for (const { jobName, statusContext, description } of skippedStatusJobs) {
51+
const job = jobs.find(j => j.name === jobName);
52+
53+
if (job && job.conclusion === 'skipped') {
54+
await github.rest.repos.createCommitStatus({
55+
owner,
56+
repo,
57+
sha: headSha,
58+
state: 'success',
59+
context: statusContext,
60+
description: description,
61+
});
62+
console.log(`Posted skipped status for ${statusContext}`);
63+
} else {
64+
console.log(`Job "${jobName}" status: ${job?.conclusion ?? 'not found'} - no status posted`);
65+
}
66+
}
67+
68+
test-report:
69+
name: Consolidated Test Report (Fork PR)
70+
runs-on: ubuntu-latest
71+
# Only run for fork PRs (non-fork PRs are handled in the main workflow)
72+
if: |
73+
github.event.workflow_run.event == 'pull_request' &&
74+
github.event.workflow_run.head_repository.full_name != github.repository
75+
permissions:
76+
checks: write
77+
actions: read
78+
steps:
79+
- name: Download test results artifact
80+
uses: actions/download-artifact@v4
81+
with:
82+
pattern: '*-results-*'
83+
path: test-results
84+
merge-multiple: false
85+
github-token: ${{ secrets.GITHUB_TOKEN }}
86+
run-id: ${{ github.event.workflow_run.id }}
87+
88+
- name: List downloaded results
89+
run: find test-results -name "*.xml" -type f 2>/dev/null || echo "No XML files found"
90+
91+
- name: Publish Test Report
92+
uses: dorny/test-reporter@v1
93+
if: always()
94+
with:
95+
name: Test Results Summary
96+
path: 'test-results/**/*.xml'
97+
reporter: java-junit
98+
fail-on-error: false
99+
fail-on-empty: false
100+
list-suites: 'failed'
101+
list-tests: 'failed'
102+
max-annotations: '50'

.github/workflows/testing.yml

Lines changed: 157 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ jobs:
1616
outputs:
1717
table_paths_changed: ${{ steps.filter.outputs.table_related_paths }}
1818
background_cb_changed: ${{ steps.filter.outputs.background_paths }}
19+
backend_cb_changed: ${{ steps.filter.outputs.backend_paths }}
1920
dcc_paths_changed: ${{ steps.filter.outputs.dcc_related_paths }}
2021
html_paths_changed: ${{ steps.filter.outputs.html_related_paths }}
22+
websocket_changed: ${{ steps.filter.outputs.websocket_paths }}
2123
steps:
2224
- name: Checkout repository
2325
uses: actions/checkout@v4
@@ -44,6 +46,21 @@ jobs:
4446
- 'tests/background_callback/**'
4547
- 'tests/async_tests/**'
4648
- 'requirements/**'
49+
backend_paths:
50+
- 'dash/backends/**'
51+
- 'tests/backend_tests/**'
52+
websocket_paths:
53+
- 'dash/backends/_fastapi.py'
54+
- 'dash/backends/_quart.py'
55+
- 'dash/backends/base_server.py'
56+
- 'dash/_callback.py'
57+
- 'dash/_callback_context.py'
58+
- 'dash/_hooks.py'
59+
- 'dash/dash.py'
60+
- '@dash-websocket-worker/**'
61+
- 'dash/dash-renderer/src/**'
62+
- 'tests/websocket/**'
63+
- 'requirements/**'
4764
4865
lint-unit:
4966
name: Lint & Unit Tests (Python ${{ matrix.python-version }})
@@ -219,7 +236,9 @@ jobs:
219236

220237
- name: Run typing tests
221238
run: |
222-
pytest tests/compliance/test_typing.py
239+
pytest \
240+
tests/compliance/test_typing.py \
241+
tests/compliance/test_callback_typing.py
223242
224243
background-callbacks:
225244
name: Run Background & Async Callback Tests (Python ${{ matrix.python-version }})
@@ -329,6 +348,80 @@ jobs:
329348
path: bgtests/test-reports/
330349
retention-days: 7
331350

351+
backend-tests:
352+
name: Run Backend Callback Tests (Python ${{ matrix.python-version }})
353+
needs: [build, changes_filter]
354+
if: |
355+
(github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev')) ||
356+
needs.changes_filter.outputs.backend_cb_changed == 'true'
357+
timeout-minutes: 30
358+
runs-on: ubuntu-latest
359+
strategy:
360+
fail-fast: false
361+
matrix:
362+
python-version: ["3.9", "3.12"]
363+
364+
services:
365+
redis:
366+
image: redis:6
367+
ports:
368+
- 6379:6379
369+
options: >-
370+
--health-cmd "redis-cli ping"
371+
--health-interval 10s
372+
--health-timeout 5s
373+
--health-retries 5
374+
375+
env:
376+
REDIS_URL: redis://localhost:6379
377+
steps:
378+
- name: Checkout repository
379+
uses: actions/checkout@v4
380+
381+
- name: Set up Node.js
382+
uses: actions/setup-node@v4
383+
with:
384+
node-version: '24'
385+
cache: 'npm'
386+
387+
- name: Install Node.js dependencies
388+
run: npm ci
389+
390+
- name: Set up Python ${{ matrix.python-version }}
391+
uses: actions/setup-python@v5
392+
with:
393+
python-version: ${{ matrix.python-version }}
394+
cache: 'pip'
395+
cache-dependency-path: requirements/*.txt
396+
397+
- name: Download built Dash packages
398+
uses: actions/download-artifact@v4
399+
with:
400+
name: dash-packages
401+
path: packages/
402+
403+
- name: Install Dash packages
404+
run: |
405+
python -m pip install --upgrade pip wheel
406+
python -m pip install "setuptools<80.0.0"
407+
find packages -name dash-*.whl -print -exec sh -c 'pip install "{}[async,ci,testing,dev,celery,diskcache,fastapi,quart]"' \;
408+
409+
- name: Setup Chrome and ChromeDriver
410+
uses: browser-actions/setup-chrome@v1
411+
with:
412+
chrome-version: stable
413+
414+
- name: Build/Setup test components
415+
run: npm run setup-tests.py
416+
417+
- name: Run Backend Callback Tests
418+
run: |
419+
mkdir bgtests
420+
cp -r tests bgtests/tests
421+
cd bgtests
422+
touch __init__.py
423+
pytest --headless --nopercyfinalize tests/backend_tests -v -s
424+
332425
table-unit:
333426
name: Table Unit/Lint Tests (Python ${{ matrix.python-version }})
334427
needs: [build, changes_filter]
@@ -451,6 +544,67 @@ jobs:
451544
path: components/dash-table/test-reports/
452545
retention-days: 7
453546

547+
websocket-tests:
548+
name: WebSocket Tests (Python ${{ matrix.python-version }})
549+
needs: [build, changes_filter]
550+
if: |
551+
(github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev')) ||
552+
needs.changes_filter.outputs.websocket_changed == 'true'
553+
timeout-minutes: 30
554+
runs-on: ubuntu-latest
555+
strategy:
556+
fail-fast: false
557+
matrix:
558+
python-version: ["3.9", "3.12"]
559+
560+
steps:
561+
- name: Checkout repository
562+
uses: actions/checkout@v4
563+
564+
- name: Set up Node.js
565+
uses: actions/setup-node@v4
566+
with:
567+
node-version: '24'
568+
cache: 'npm'
569+
570+
- name: Install Node.js dependencies
571+
run: npm ci
572+
573+
- name: Set up Python ${{ matrix.python-version }}
574+
uses: actions/setup-python@v5
575+
with:
576+
python-version: ${{ matrix.python-version }}
577+
cache: 'pip'
578+
cache-dependency-path: requirements/*.txt
579+
580+
- name: Download built Dash packages
581+
uses: actions/download-artifact@v4
582+
with:
583+
name: dash-packages
584+
path: packages/
585+
586+
- name: Install Dash packages
587+
run: |
588+
python -m pip install --upgrade pip wheel
589+
python -m pip install "setuptools<80.0.0"
590+
find packages -name dash-*.whl -print -exec sh -c 'pip install "{}[ci,testing,dev,fastapi,quart]"' \;
591+
592+
- name: Setup Chrome and ChromeDriver
593+
uses: browser-actions/setup-chrome@v1
594+
with:
595+
chrome-version: stable
596+
597+
- name: Build/Setup test components
598+
run: npm run setup-tests.py
599+
600+
- name: Run WebSocket tests
601+
run: |
602+
mkdir wstests
603+
cp -r tests wstests/tests
604+
cd wstests
605+
touch __init__.py
606+
pytest --headless --nopercyfinalize tests/websocket -v -s
607+
454608
test-main:
455609
name: Main Dash Tests (Python ${{ matrix.python-version }}, Group ${{ matrix.test-group }})
456610
needs: build
@@ -918,30 +1072,6 @@ jobs:
9181072
if: env.PERCY_TOKEN == ''
9191073
run: echo "::notice::Skipping Percy finalize (no token available - likely a fork PR)"
9201074

921-
report-table-percy-skipped:
922-
name: Report Percy Table Skipped
923-
needs: table-visual-test
924-
runs-on: ubuntu-latest
925-
if: |
926-
always() &&
927-
github.event_name == 'pull_request' &&
928-
needs.table-visual-test.result == 'skipped'
929-
permissions:
930-
statuses: write
931-
steps:
932-
- name: Post success status for percy/dash-table-test
933-
uses: actions/github-script@v7
934-
with:
935-
script: |
936-
await github.rest.repos.createCommitStatus({
937-
owner: context.repo.owner,
938-
repo: context.repo.repo,
939-
sha: context.payload.pull_request.head.sha,
940-
state: 'success',
941-
context: 'percy/dash-table-test',
942-
description: 'Skipped — no dash-table changes',
943-
});
944-
9451075
test-report:
9461076
name: Consolidated Test Report
9471077
needs: [lint-unit, test-main, dcc-test, html-test, table-server, background-callbacks, test-typing]
@@ -963,7 +1093,8 @@ jobs:
9631093

9641094
- name: Publish Test Report
9651095
uses: dorny/test-reporter@v1
966-
if: always()
1096+
# Skip for fork PRs - handled by post-test-status.yml workflow_run
1097+
if: always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
9671098
with:
9681099
name: Test Results Summary
9691100
path: 'test-results/**/*.xml'

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,4 @@ packages/
9393
!components/dash-core-components/tests/integration/upload/upload-assets/upft001.csv
9494
!components/dash-table/tests/assets/*.csv
9595
!components/dash-table/tests/selenium/assets/*.csv
96+
dash_config.json
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Dash websocket worker
2+
3+
Worker for websocket based callbacks.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "@plotly/dash-websocket-worker",
3+
"version": "1.0.0",
4+
"description": "SharedWorker for WebSocket-based Dash callbacks",
5+
"main": "dist/index.js",
6+
"types": "dist/index.d.ts",
7+
"scripts": {
8+
"build": "webpack --mode production",
9+
"build:dev": "webpack --mode development",
10+
"watch": "webpack --mode development --watch",
11+
"clean": "rm -rf dist"
12+
},
13+
"files": [
14+
"dist"
15+
],
16+
"keywords": [
17+
"dash",
18+
"websocket",
19+
"sharedworker"
20+
],
21+
"author": "Plotly",
22+
"license": "MIT",
23+
"devDependencies": {
24+
"typescript": "^5.0.0",
25+
"webpack": "^5.0.0",
26+
"webpack-cli": "^5.0.0",
27+
"ts-loader": "^9.0.0"
28+
}
29+
}

0 commit comments

Comments
 (0)