
Panel 1.10.0은 Material UI 컴포넌트를 panel.ui로 통합하고, FastAPI·Django와 연결할 수 있는 자체 ASGI 서버를 추가했다. 기존 앱을 옮기는 panel migrate 명령과 컴포넌트의 자바스크립트 자원을 필요할 때 불러오는 기능도 포함한다.
panel.ui는 Material UI 컴포넌트와 Material UI 대응 항목이 없는 기존 Panel 컴포넌트를 한 네임스페이스에서 제공한다. 기존 API와 디자인은 그대로 유지되며, 새 네임스페이스는 선택해 사용할 수 있다. Material과 기존 컴포넌트를 한 앱에서 섞어 쓸 수 있어 단계적으로 옮길 수 있다. panel migrate는 가져오기 경로와 일부 인자, 호환되는 템플릿을 바꾸며, 안전하게 변환할 수 없는 항목은 수동 검토 대상으로 남긴다. CSS와 사용자 정의 디자인 등은 직접 수정해야 한다.
panel serve는 tornado를 기본 서버로 유지하면서 asgi와 fastapi 선택지를 추가했다. ASGI 서버에서는 Tornado 요청 핸들러로 구현된 --rest-provider, --enable-xsrf-cookies, --num-procs 옵션을 사용할 수 없으며, 해당 옵션을 지정하면 오류가 발생한다. FastAPI·Django 통합은 더 이상 bokeh-fastapi와 bokeh-django에 의존하지 않는다. pn.extension('tabulator')는 자원 사전 로딩 용도로 계속 쓸 수 있지만, 컴포넌트 사용 전에 반드시 지정할 필요는 없다.
이 밖에 서버 페이지에 테마와 로고를 적용하는 설정, 별도로 보호할 수 있는 /admin 대시보드, Narwhals가 지원하는 DataFrame 렌더링이 추가됐다. Tabulator는 507KB의 bokeh-tables 번들을 기본으로 불러오지 않는다. Markdown·HTML에 텍스트를 스트리밍할 때 토큰당 렌더링 비용이 대체로 일정해지도록 개선했으며, JSComponent와 ReactComponent의 렌더링 작업도 개선했다.
Panel 1.10.0은 Bokeh 3.10과 Python 3.12 이상이 필요하고 Python 3.15를 지원한다. Python 3.10·3.11 및 Bokeh 3.8·3.9 지원은 중단됐다. 설치는 conda install panel 또는 pip install panel로 할 수 있다. 전체 변경 사항은 Panel 1.10.0 변경 기록에서 확인할 수 있다.
부록: 원문 예시
pages = { 'Inputs': ('edit_note', inputs), 'Selection': ('checklist', selection), 'Sliders': ('tune', sliders), 'Feedback': ('notifications', feedback), 'Data': ('table_chart', table), 'Code': ('code', editor), } menu = pn.ui.MenuList( items=[{'label': name, 'icon': icon} for name, (icon, _) in pages.items()], active=(0,), sizing_mode='stretch_width', ) pn.ui.Page( logo='images/panel_logo.png', sidebar=[menu], sidebar_width=140, main=show_selected(menu, pages), height=440, ).servable()
import panel as pn pn.extension(template='page') slider = pn.ui.IntSlider(label='Stars', start=0, end=10, value=3) slider.servable(target='sidebar') pn.panel(pn.bind(lambda n: '⭐' * n, slider)).servable(target='main')
import panel as pn pn.extension(design='bootstrap') button = pn.widgets.Button(name='Run', button_type='primary') slider = pn.widgets.IntSlider(name='Stars', start=0, end=10, value=3) pn.template.FastListTemplate( title='Stars', sidebar=[button], main=[slider.rx() * '⭐'], ).servable()
-pn.extension(design='bootstrap') +pn.extension() -button = pn.widgets.Button(name='Run', button_type='primary') -slider = pn.widgets.IntSlider(name='Stars', start=0, end=10, value=3) +button = pn.ui.Button(label='Run', color='primary') +slider = pn.ui.IntSlider(label='Stars', start=0, end=10, value=3) -pn.template.FastListTemplate( +pn.ui.Page(
import panel as pn from panel.io.asgi import build_asgi_app def stars(): slider = pn.ui.IntSlider(label='Stars', start=0, end=10, value=3) return slider.rx() * '⭐' app = build_asgi_app({'/stars': stars})
import panel as pn from fastapi import FastAPI from panel.io.fastapi import add_application app = FastAPI() @app.get("/") async def read_root(): return {"Hello": "World"} @add_application('/panel', app=app, title='My Panel App') def create_panel_app(): slider = pn.ui.IntSlider(label='Slider', start=0, end=10, value=3) return slider.rx() * '⭐'
add_applications( {"/panel_app": create_panel_app}, app=app, oauth_provider='azure', oauth_key='...', oauth_secret='...', oauth_encryption_key='...', cookie_secret='...', )
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요