Skip to content

Commit 3e17d44

Browse files
authored
Merge branch 'main' into feat/smart-followup-suggestions
2 parents 40df87c + 84605f8 commit 3e17d44

27 files changed

Lines changed: 1854 additions & 105 deletions

File tree

.github/workflows/build.yaml

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ on:
66
- "v[0-9]+.[0-9]+.[0-9]+a[0-9]+"
77
- "v[0-9]+.[0-9]+.[0-9]+b[0-9]+"
88
- "v[0-9]+.[0-9]+.[0-9]+rc[0-9]+"
9-
# Dry-run only
109
workflow_dispatch:
1110
schedule:
1211
- cron: "0 17 * * SUN"
@@ -16,8 +15,8 @@ defaults:
1615
shell: bash -e {0}
1716

1817
env:
19-
PYTHON_VERSION: "3.11"
2018
PACKAGE: "lumen"
19+
PYTHON_VERSION: "3.11"
2120

2221
jobs:
2322
waiting_room:
@@ -48,45 +47,35 @@ jobs:
4847
install: false
4948
- name: conda build
5049
run: pixi run -e build build-conda
51-
- uses: actions/upload-artifact@v4
50+
- uses: actions/upload-artifact@v7
5251
if: always()
5352
with:
54-
name: conda
55-
path: dist/*.tar.bz2
53+
name: artifacts-conda
54+
path: dist/*.conda
5655
if-no-files-found: error
5756

5857
conda_publish:
5958
name: Publish Conda
6059
runs-on: ubuntu-latest
6160
needs: [conda_build, waiting_room]
6261
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
63-
defaults:
64-
run:
65-
shell: bash -el {0}
6662
steps:
67-
- uses: actions/download-artifact@v4
63+
- uses: actions/download-artifact@v8
6864
with:
69-
name: conda
65+
name: artifacts-conda
7066
path: dist/
71-
- name: Set environment variables
67+
- name: anaconda setup
7268
run: |
73-
echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
74-
echo "CONDA_FILE=$(ls dist/*.tar.bz2)" >> $GITHUB_ENV
75-
- uses: conda-incubator/setup-miniconda@v3
76-
with:
77-
miniconda-version: "latest"
78-
channels: "conda-forge"
79-
- name: conda setup
69+
pipx install anaconda-client
70+
binstar --version
71+
- name: anaconda dev upload
72+
if: contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc')
8073
run: |
81-
conda install -y anaconda-client
82-
- name: conda dev upload
83-
if: contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')
74+
binstar --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev dist/*.conda
75+
- name: anaconda upload
76+
if: (!(contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc')))
8477
run: |
85-
anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev $CONDA_FILE
86-
- name: conda main upload
87-
if: (!(contains(env.TAG, 'a') || contains(env.TAG, 'b') || contains(env.TAG, 'rc')))
88-
run: |
89-
anaconda --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main $CONDA_FILE
78+
binstar --token ${{ secrets.CONDA_UPLOAD_TOKEN }} upload --user pyviz --label=dev --label=main dist/*.conda
9079
9180
pip_build:
9281
name: Build PyPI
@@ -100,10 +89,10 @@ jobs:
10089
install: false
10190
- name: Build package
10291
run: pixi run -e build build-pip
103-
- uses: actions/upload-artifact@v4
92+
- uses: actions/upload-artifact@v7
10493
if: always()
10594
with:
106-
name: pip
95+
name: artifacts-pip
10796
path: dist/
10897
if-no-files-found: error
10998

@@ -112,12 +101,12 @@ jobs:
112101
runs-on: "ubuntu-latest"
113102
needs: [pip_build]
114103
steps:
115-
- uses: actions/setup-python@v5
104+
- uses: actions/setup-python@v6
116105
with:
117106
python-version: ${{ env.PYTHON_VERSION }}
118-
- uses: actions/download-artifact@v4
107+
- uses: actions/download-artifact@v8
119108
with:
120-
name: pip
109+
name: artifacts-pip
121110
path: dist/
122111
- name: Install package
123112
run: python -m pip install dist/*.whl
@@ -129,14 +118,46 @@ jobs:
129118
runs-on: ubuntu-latest
130119
needs: [pip_build, waiting_room]
131120
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
121+
permissions:
122+
id-token: write
132123
steps:
133-
- uses: actions/download-artifact@v4
124+
- uses: actions/download-artifact@v8
134125
with:
135-
name: pip
126+
name: artifacts-pip
136127
path: dist/
137128
- name: Publish to PyPI
138129
uses: pypa/gh-action-pypi-publish@release/v1
130+
131+
announce:
132+
name: Announce GitHub
133+
runs-on: ubuntu-latest
134+
needs: [waiting_room]
135+
permissions:
136+
contents: write
137+
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
138+
env:
139+
TAG: ${{ github.ref_name }}
140+
steps:
141+
- uses: actions/checkout@v6
142+
- uses: actions/download-artifact@v8
139143
with:
140-
user: ${{ secrets.PPU }}
141-
password: ${{ secrets.PPP }}
142-
repository-url: "https://upload.pypi.org/legacy/"
144+
pattern: artifacts-*
145+
path: artifacts/
146+
merge-multiple: true
147+
- name: Extract changelog section
148+
run: |
149+
awk -v ver="## Version ${TAG#v}" '
150+
$0 == ver {flag=1; next}
151+
/^#{2} Version / && flag {exit}
152+
flag && !/^(\*\*.*\*\*)$/
153+
' CHANGELOG.md | tee RELEASE_BODY.md
154+
- name: Create draft GitHub release with dist artifacts
155+
if: (!(contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc')))
156+
env:
157+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
158+
run: |
159+
gh release create "$TAG" \
160+
--title "Version ${TAG#v}" \
161+
--notes-file RELEASE_BODY.md \
162+
--draft \
163+
artifacts/*

.github/workflows/docs.yaml

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -46,38 +46,29 @@ jobs:
4646
environments: docs
4747
- name: Build documentation
4848
run: pixi run -e docs docs-build
49-
- uses: actions/upload-artifact@v4
49+
- uses: actions/upload-artifact@v7
5050
if: always()
5151
with:
5252
name: docs
5353
if-no-files-found: error
5454
path: builtdocs
55-
- name: Set output
56-
id: vars
57-
run: echo "tag=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
5855

5956
docs_publish:
6057
name: Publish Documentation
6158
runs-on: "ubuntu-latest"
6259
needs: [docs_build]
6360
env:
6461
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
65-
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
66-
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
67-
AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
6862
steps:
69-
- uses: actions/download-artifact@v4
63+
- uses: actions/download-artifact@v8
7064
with:
7165
name: docs
7266
path: builtdocs/
73-
- name: Set output
74-
id: vars
75-
run: echo "tag=${{ needs.docs_build.outputs.tag }}" >> $GITHUB_OUTPUT
7667
- name: upload dev
77-
uses: peaceiris/actions-gh-pages@v3
68+
uses: peaceiris/actions-gh-pages@v4
7869
if: |
7970
(github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'dev') ||
80-
(github.event_name == 'push' && (contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
71+
(github.event_name == 'push' && (contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc')))
8172
with:
8273
personal_token: ${{ secrets.ACCESS_TOKEN }}
8374
external_repository: holoviz-dev/lumen
@@ -86,8 +77,8 @@ jobs:
8677
- name: upload main
8778
if: |
8879
(github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'main') ||
89-
(github.event_name == 'push' && !(contains(steps.vars.outputs.tag, 'a') || contains(steps.vars.outputs.tag, 'b') || contains(steps.vars.outputs.tag, 'rc')))
90-
uses: peaceiris/actions-gh-pages@v3
80+
(github.event_name == 'push' && !(contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc')))
81+
uses: peaceiris/actions-gh-pages@v4
9182
with:
9283
github_token: ${{ secrets.GITHUB_TOKEN }}
9384
publish_dir: ./builtdocs

.github/workflows/gallery.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ jobs:
2626
shell: bash -el {0}
2727
steps:
2828
- name: Checkout
29-
uses: actions/checkout@v3
29+
uses: actions/checkout@v6
3030
with:
3131
fetch-depth: 0
3232
- name: Setup Python
33-
uses: actions/setup-python@v4
33+
uses: actions/setup-python@v6
3434
with:
3535
python-version: '3.11'
3636
- name: Set and echo git ref
@@ -40,7 +40,7 @@ jobs:
4040
run: |
4141
echo "Deploying from ref $HEAD_BRANCH"
4242
echo "tag=$HEAD_BRANCH" >> $GITHUB_OUTPUT
43-
- uses: conda-incubator/setup-miniconda@v2
43+
- uses: conda-incubator/setup-miniconda@v3
4444
with:
4545
miniconda-version: "latest"
4646
auto-update-conda: true

.github/workflows/lock.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
action:
1717
runs-on: ubuntu-latest
1818
steps:
19-
- uses: dessant/lock-threads@v4
19+
- uses: dessant/lock-threads@v6
2020
with:
2121
issue-inactive-days: "100"
2222
pr-inactive-days: "100"

.github/workflows/test.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
if: needs.setup.outputs.img_change == 'true'
4848
with:
4949
extra_args: -a --hook-stage manual oxipng || true --
50-
- uses: stefanzweifel/git-auto-commit-action@v4
50+
- uses: stefanzweifel/git-auto-commit-action@v7
5151
if: needs.setup.outputs.img_change == 'true'
5252
with:
5353
commit_message: "Optimize PNG images (lossless)"
@@ -60,10 +60,10 @@ jobs:
6060
img_change: ${{ steps.filter.outputs.img }}
6161
matrix: ${{ env.MATRIX }}
6262
steps:
63-
- uses: actions/checkout@v4
63+
- uses: actions/checkout@v6
6464
if: github.event_name != 'pull_request'
6565
- name: Check for code changes
66-
uses: dorny/paths-filter@v3
66+
uses: dorny/paths-filter@v4
6767
id: filter
6868
with:
6969
filters: |
@@ -129,7 +129,7 @@ jobs:
129129
- name: Test Unit
130130
run: |
131131
pixi run -e ${{ matrix.environment }} test-unit $COV
132-
- uses: codecov/codecov-action@v4
132+
- uses: codecov/codecov-action@v5
133133
with:
134134
token: ${{ secrets.CODECOV_TOKEN }}
135135

docs/configuration/sources.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ ui.servable()
2929
|--------|---------|
3030
| Files | CSV, Parquet, JSON (local or URL) |
3131
| DuckDB | Local SQL queries on files |
32+
| xarray | N-dimensional scientific data (NetCDF, Zarr, HDF5) |
3233
| Snowflake | Cloud data warehouse |
3334
| BigQuery | Google's data warehouse |
3435
| PostgreSQL | PostgreSQL via SQLAlchemy |
@@ -173,6 +174,45 @@ source = DuckDBSource(
173174

174175
1. Required for HTTP/S3 access
175176

177+
### xarray for scientific data
178+
179+
Query N-dimensional scientific datasets (NetCDF, Zarr, HDF5) with SQL via Apache DataFusion:
180+
181+
``` bash title="Install dependencies"
182+
pip install lumen[xarray]
183+
```
184+
185+
``` py title="Query a NetCDF file"
186+
from lumen.sources.xarray_sql import XArraySQLSource
187+
import lumen.ai as lmai
188+
189+
source = XArraySQLSource(uri='air_temperature.nc')
190+
191+
ui = lmai.ExplorerUI(data=source)
192+
ui.servable()
193+
```
194+
195+
Each data variable in the dataset becomes a separate SQL table with coordinate columns:
196+
197+
``` py title="Direct SQL queries"
198+
source = XArraySQLSource(uri='air_temperature.nc')
199+
source.get_tables() # ['air']
200+
201+
df = source.execute(
202+
"SELECT lat, lon, AVG(air) as avg_temp "
203+
"FROM air GROUP BY lat, lon"
204+
)
205+
```
206+
207+
**Select specific variables:**
208+
209+
``` py hl_lines="3"
210+
source = XArraySQLSource(
211+
uri='climate_data.nc',
212+
variables=['temperature', 'pressure']
213+
)
214+
```
215+
176216
### Multiple sources
177217

178218
``` py title="Mix sources"

docs/extending.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# :material-puzzle-plus: Extending Lumen
2+
3+
Lumen's core building blocks—[Sources](configuration/sources.md), [Agents](configuration/agents.md), [Tools](configuration/tools.md), and [Analyses](configuration/analyses.md)—are all subclassable Python classes. If you've built a custom component and want to share it as a reusable, installable Python package, the **Panel Extension Copier Template** gives you a fully configured project scaffold to do just that.
4+
5+
### What is the Panel Extension Copier Template?
6+
7+
The [`copier-template-panel-extension`](https://github.com/panel-extensions/copier-template-panel-extension) is a [Copier](https://copier.readthedocs.io/en/stable/) template that scaffolds a fully configured Python package for Panel and Lumen extensions. It gives you:
8+
9+
- **pytest** for testing
10+
- **Zensical + mkdocstrings** for automatic API docs hosted on GitHub Pages
11+
- **GitHub Actions** CI/CD for automated testing and publishing
12+
- **Pixi** for reproducible environment management
13+
14+
### Quickstart
15+
16+
Make sure you have [Pixi](https://pixi.sh) installed, then run:
17+
18+
```bash
19+
pixi exec --spec copier --spec ruamel.yaml -- \
20+
copier copy --trust \
21+
https://github.com/panel-extensions/copier-template-panel-extension \
22+
lumen-name-of-extension
23+
```
24+
25+
You'll be prompted for a few details such as extension type, project slug, and author info. Choose **Lumen** as the extension type when asked, and select `py311` or higher for the minimum Python version—Lumen requires Python 3.11+.
26+
27+
From there, follow the template's [step-by-step guide](https://github.com/panel-extensions/copier-template-panel-extension#getting-started) to set up GitHub Pages docs, link to PyPI, and publish your first release with a git tag.
28+
29+
---
30+
31+
## Further Reading
32+
33+
- [Data Sources](configuration/sources.md) — built-in sources and how to configure them
34+
- [Agents](configuration/agents.md) — customizing agent behavior
35+
- [Tools](configuration/tools.md) — adding domain-specific tools
36+
- [Analyses](configuration/analyses.md) — deterministic analysis functions
37+
- [Panel Extension Copier Template on GitHub](https://github.com/panel-extensions/copier-template-panel-extension)

0 commit comments

Comments
 (0)