Skip to content

Commit

Permalink
Merge branch 'main' into leaflet
Browse files Browse the repository at this point in the history
# Conflicts:
#	DEPENDENCIES.md
#	npm.json
  • Loading branch information
falkoschindler committed Dec 7, 2023
2 parents c3f1854 + 2fce6cf commit 5373df4
Show file tree
Hide file tree
Showing 721 changed files with 80,600 additions and 82,805 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
uses: softprops/action-gh-release@v1
id: create_release
with:
draft: false
draft: true
prerelease: false
name: ${{ env.VERSION }}
tag_name: ${{ env.VERSION }}
Expand Down Expand Up @@ -115,6 +115,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
ref: main

- name: Set up Python
uses: actions/setup-python@v2
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
test:
strategy:
matrix:
python: ["3.8", "3.9", "3.10", "3.11"]
python: ["3.8", "3.9", "3.10", "3.11", "3.12"]
fail-fast: false
runs-on: ubuntu-latest
timeout-minutes: 40
Expand All @@ -19,9 +19,10 @@ jobs:
- name: set up Poetry
uses: abatilo/[email protected]
with:
poetry-version: "1.3.1"
poetry-version: "1.6.1"
- name: install dependencies
run: |
set -x
poetry config virtualenvs.create false
poetry install --all-extras
# install packages to run the examples
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/update_citation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import yaml


def get_infos() -> Tuple[str]:
def get_infos() -> Tuple[str, str, str]:
headers = {
'Accept': 'application/json',
}
Expand All @@ -24,8 +24,9 @@ def get_infos() -> Tuple[str]:
except Exception:
print('Error while getting the Zenodo infos')
sys.exit(1)
data = response.json()[0]['metadata']
return data['doi'], data['version'], data['publication_date']
data = response.json()
metadata = data['hits']['hits'][0]['metadata']
return str(metadata['doi']), str(metadata['version']), str(metadata['publication_date'])


if __name__ == '__main__':
Expand Down
15 changes: 15 additions & 0 deletions .syncignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
__pycache__/
*.egg-info/
.*.swp
dist
/test.py
*.pickle
tests/screenshots/
tests/media/
venv
.idea
.nicegui/
*.sqlite*
.DS_Store
.pytest_cache/
.vscode/
.github/
tests/
.git/
.mypy_cache/
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"prettier.printWidth": 120,
"pylint.args": [
"--disable=C0103", // Invalid name (e.g., variable/function/class naming conventions)
"--disable=C0111", // Missing docstring (in function/class/method)
"--disable=C0114", // Missing module docstring
"--disable=C0115", // Missing class docstring
"--disable=C0301", // Line too long (exceeds character limit)
"--disable=C0302", // Too many lines in module
"--disable=R0801", // Similar lines in files
Expand Down
6 changes: 3 additions & 3 deletions CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ authors:
given-names: Rodja
orcid: https://orcid.org/0009-0009-4735-6227
title: 'NiceGUI: Web-based user interfaces with Python. The nice way.'
version: v1.3.16
date-released: '2023-10-06'
version: v1.4.4
date-released: '2023-12-04'
url: https://github.com/zauberzeug/nicegui
doi: 10.5281/zenodo.8413612
doi: 10.5281/zenodo.10256862
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,10 @@ If you plan to implement a new element you can follow these suggestions:
5. Look at other similar elements and how they are implemented in `nicegui/elements`.
6. Create a new file with your new element alongside the existing ones.
7. Make sure your element works as expected.
8. Add documentation in [website/documentation.py](https://github.com/zauberzeug/nicegui/blob/main/website/documentation.py).
By calling the `element_demo(...)` function with an element as a parameter the docstring is used as a description.
8. Add a documentation file in `website/documentation/content`.
By calling the `@doc.demo(...)` function with an element as a parameter the docstring is used as a description.
The docstrings are written in restructured-text.
Refer to the new documentation page using `@doc.intro(...)` in any documentation section `website/documentation/content/section_*.py`.
9. Create a pull-request (see below).

### Additional Demos
Expand Down
21 changes: 10 additions & 11 deletions DEPENDENCIES.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
# Included Web Dependencies

- vue: 3.3.4 ([MIT](https://opensource.org/licenses/MIT))
- quasar: 2.12.2 ([MIT](https://opensource.org/licenses/MIT))
- tailwindcss: 3.3.2 ([MIT](https://opensource.org/licenses/MIT))
- socket.io: 4.7.1 ([MIT](https://opensource.org/licenses/MIT))
- es-module-shims: 1.7.3 ([MIT](https://opensource.org/licenses/MIT))
- aggrid: 30.0.3 ([MIT](https://opensource.org/licenses/MIT))
- vue: 3.3.6 ([MIT](https://opensource.org/licenses/MIT))
- quasar: 2.13.0 ([MIT](https://opensource.org/licenses/MIT))
- tailwindcss: 3.2.0 ([MIT](https://opensource.org/licenses/MIT))
- socket.io: 4.7.2 ([MIT](https://opensource.org/licenses/MIT))
- es-module-shims: 1.8.0 ([MIT](https://opensource.org/licenses/MIT))
- aggrid: 30.2.0 ([MIT](https://opensource.org/licenses/MIT))
- echarts: 5.4.3 ([Apache-2.0](https://opensource.org/licenses/Apache-2.0))
- highcharts: 11.1.0 ([https://www.highcharts.com/license](https://www.highcharts.com/license))
- leaflet: 1.9.4 ([BSD-2-Clause](https://opensource.org/licenses/BSD-2-Clause))
- mermaid: 10.2.4 ([MIT](https://opensource.org/licenses/MIT))
- mermaid: 10.5.1 ([MIT](https://opensource.org/licenses/MIT))
- nipplejs: 0.10.1 ([MIT](https://opensource.org/licenses/MIT))
- plotly: 2.24.3 ([MIT](https://opensource.org/licenses/MIT))
- three: 0.154.0 ([MIT](https://opensource.org/licenses/MIT))
- plotly: 2.27.0 ([MIT](https://opensource.org/licenses/MIT))
- three: 0.157.0 ([MIT](https://opensource.org/licenses/MIT))
- tween: 21.0.0 ([MIT](https://opensource.org/licenses/MIT))
- vanilla-jsoneditor: 0.18.0 ([ISC](https://opensource.org/licenses/ISC))
- vanilla-jsoneditor: 0.18.10 ([ISC](https://opensource.org/licenses/ISC))
6 changes: 3 additions & 3 deletions development.dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM python:3.8-slim

RUN apt update && apt install curl -y
RUN apt update && apt install curl build-essential -y

# We use Poetry for dependency management
RUN curl -sSL https://install.python-poetry.org | python3 - && \
Expand All @@ -10,7 +10,7 @@ RUN curl -sSL https://install.python-poetry.org | python3 - && \

WORKDIR /app

COPY ./pyproject.toml ./poetry.lock* main.py ./
RUN poetry install --no-root --all-extras
COPY . .
RUN poetry install --all-extras

CMD python3 -m debugpy --listen 5678 main.py
5 changes: 2 additions & 3 deletions examples/authentication/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
from fastapi.responses import RedirectResponse
from starlette.middleware.base import BaseHTTPMiddleware

import nicegui.globals
from nicegui import app, ui
from nicegui import Client, app, ui

# in reality users passwords would obviously need to be hashed
passwords = {'user1': 'pass1', 'user2': 'pass2'}
Expand All @@ -28,7 +27,7 @@ class AuthMiddleware(BaseHTTPMiddleware):

async def dispatch(self, request: Request, call_next):
if not app.storage.user.get('authenticated', False):
if request.url.path in nicegui.globals.page_routes.values() and request.url.path not in unrestricted_page_routes:
if request.url.path in Client.page_routes.values() and request.url.path not in unrestricted_page_routes:
app.storage.user['referrer_path'] = request.url.path # remember where the user wanted to go
return RedirectResponse('/login')
return await call_next(request)
Expand Down
6 changes: 3 additions & 3 deletions examples/chat_app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@


@ui.refreshable
async def chat_messages(own_id: str) -> None:
def chat_messages(own_id: str) -> None:
for user_id, avatar, text, stamp in messages:
ui.chat_message(text=text, stamp=stamp, avatar=avatar, sent=own_id == user_id)
await ui.run_javascript('window.scrollTo(0, document.body.scrollHeight)', respond=False)
ui.run_javascript('window.scrollTo(0, document.body.scrollHeight)')


@ui.page('/')
Expand All @@ -39,6 +39,6 @@ def send() -> None:

await client.connected() # chat_messages(...) uses run_javascript which is only possible after connecting
with ui.column().classes('w-full max-w-2xl mx-auto items-stretch'):
await chat_messages(user_id)
chat_messages(user_id)

ui.run()
48 changes: 48 additions & 0 deletions examples/chat_with_ai/log_callback_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from typing import Any, Dict, Optional

from langchain.callbacks.base import BaseCallbackHandler
from langchain.schema import AgentAction, AgentFinish

from nicegui import ui


class NiceGuiLogElementCallbackHandler(BaseCallbackHandler):
"""Callback Handler that writes to a log element."""

def __init__(self, log_element: ui.log) -> None:
"""Initialize callback handler."""
self.log = log_element

def on_chain_start(self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any) -> None:
"""Print out that we are entering a chain."""
self.log.push(f'\n\n> Entering new {serialized["id"][-1]} chain...')

def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None:
"""Print out that we finished a chain."""
self.log.push('\n> Finished chain.')
self.log.push(f'\nOutputs: {outputs}')

def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any:
"""Run on agent action."""
self.log.push(action.log)

def on_tool_end(self,
output: str,
observation_prefix: Optional[str] = None,
llm_prefix: Optional[str] = None,
**kwargs: Any,
) -> None:
"""If not the final action, print out observation."""
if observation_prefix is not None:
self.log.push(f'\n{observation_prefix}')
self.log.push(output)
if llm_prefix is not None:
self.log.push(f'\n{llm_prefix}')

def on_text(self, text: str, **kwargs: Any) -> None:
"""Run when agent ends."""
self.log.push(text)

def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:
"""Run on agent end."""
self.log.push(finish.log)
49 changes: 30 additions & 19 deletions examples/chat_with_ai/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,57 @@

from langchain.chains import ConversationChain
from langchain.chat_models import ChatOpenAI
from log_callback_handler import NiceGuiLogElementCallbackHandler

from nicegui import Client, ui
from nicegui import context, ui

OPENAI_API_KEY = 'not-set' # TODO: set your OpenAI API key here

llm = ConversationChain(llm=ChatOpenAI(model_name='gpt-3.5-turbo', openai_api_key=OPENAI_API_KEY))

messages: List[Tuple[str, str]] = []
thinking: bool = False

@ui.page('/')
def main():
llm = ConversationChain(llm=ChatOpenAI(model_name='gpt-3.5-turbo', openai_api_key=OPENAI_API_KEY))

@ui.refreshable
async def chat_messages() -> None:
for name, text in messages:
ui.chat_message(text=text, name=name, sent=name == 'You')
if thinking:
ui.spinner(size='3rem').classes('self-center')
await ui.run_javascript('window.scrollTo(0, document.body.scrollHeight)', respond=False)
messages: List[Tuple[str, str]] = []
thinking: bool = False

@ui.refreshable
def chat_messages() -> None:
for name, text in messages:
ui.chat_message(text=text, name=name, sent=name == 'You')
if thinking:
ui.spinner(size='3rem').classes('self-center')
if context.get_client().has_socket_connection:
ui.run_javascript('window.scrollTo(0, document.body.scrollHeight)')

@ui.page('/')
async def main(client: Client):
async def send() -> None:
global thinking
nonlocal thinking
message = text.value
messages.append(('You', text.value))
thinking = True
text.value = ''
chat_messages.refresh()

response = await llm.arun(message)
response = await llm.arun(message, callbacks=[NiceGuiLogElementCallbackHandler(log)])
messages.append(('Bot', response))
thinking = False
chat_messages.refresh()

anchor_style = r'a:link, a:visited {color: inherit !important; text-decoration: none; font-weight: 500}'
ui.add_head_html(f'<style>{anchor_style}</style>')
await client.connected()

with ui.column().classes('w-full max-w-2xl mx-auto items-stretch'):
await chat_messages()
# the queries below are used to expand the contend down to the footer (content can then use flex-grow to expand)
ui.query('.q-page').classes('flex')
ui.query('.nicegui-content').classes('w-full')

with ui.tabs().classes('w-full') as tabs:
chat_tab = ui.tab('Chat')
logs_tab = ui.tab('Logs')
with ui.tab_panels(tabs, value=chat_tab).classes('w-full max-w-2xl mx-auto flex-grow items-stretch'):
with ui.tab_panel(chat_tab).classes('items-stretch'):
chat_messages()
with ui.tab_panel(logs_tab):
log = ui.log().classes('w-full h-full')

with ui.footer().classes('bg-white'), ui.column().classes('w-full max-w-3xl mx-auto my-6'):
with ui.row().classes('w-full no-wrap items-center'):
Expand All @@ -54,4 +64,5 @@ async def send() -> None:
ui.markdown('simple chat app built with [NiceGUI](https://nicegui.io)') \
.classes('text-xs self-end mr-8 m-[-1em] text-primary')


ui.run(title='Chat with GPT-3 (example)')
9 changes: 6 additions & 3 deletions examples/custom_binding/main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env python3
import random
from typing import Optional
from typing import Optional, cast

from typing_extensions import Self

from nicegui import ui
from nicegui.binding import BindableProperty, bind_from
Expand All @@ -10,13 +12,14 @@ class colorful_label(ui.label):
"""A label with a bindable background color."""

# This class variable defines what happens when the background property changes.
background = BindableProperty(on_change=lambda sender, value: sender.on_background_change(value))
background = BindableProperty(
on_change=lambda sender, value: cast(Self, sender)._handle_background_change(value))

def __init__(self, text: str = '') -> None:
super().__init__(text)
self.background: Optional[str] = None # initialize the background property

def on_background_change(self, bg_class: str) -> None:
def _handle_background_change(self, bg_class: str) -> None:
"""Update the classes of the label when the background property changes."""
self._classes = [c for c in self._classes if not c.startswith('bg-')]
self._classes.append(bg_class)
Expand Down
8 changes: 4 additions & 4 deletions examples/descope_auth/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def about() -> Dict[str, Any]:

async def logout() -> None:
"""Logout the user."""
result = await ui.run_javascript('return await sdk.logout()', respond=True)
result = await ui.run_javascript('return await sdk.logout()')
if result['code'] == 200:
app.storage.user['descope'] = None
else:
Expand Down Expand Up @@ -64,7 +64,7 @@ async def content(client: Client):
await client.connected()
if await self._is_logged_in():
if self.path == self.LOGIN_PATH:
await self._refresh()
self._refresh()
ui.open('/')
return
else:
Expand Down Expand Up @@ -96,8 +96,8 @@ async def _is_logged_in() -> bool:
return False

@staticmethod
async def _refresh() -> None:
await ui.run_javascript('sdk.refresh()', respond=False)
def _refresh() -> None:
ui.run_javascript('sdk.refresh()')


def login_page(func: Callable[..., Any]) -> Callable[..., Any]:
Expand Down
Loading

0 comments on commit 5373df4

Please sign in to comment.