Skip to content

Commit

Permalink
Merge branch 'main' into dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
falkoschindler committed Aug 7, 2024
2 parents 8006d5b + 277ada6 commit 4c59444
Show file tree
Hide file tree
Showing 102 changed files with 3,487 additions and 969 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.8
FROM --platform=linux/amd64 python:3.8

ENV POETRY_VERSION=1.6.1 \
POETRY_NO_INTERACTION=1 \
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.4.26
date-released: '2024-05-27'
version: v1.4.30
date-released: '2024-07-26'
url: https://github.com/zauberzeug/nicegui
doi: 10.5281/zenodo.11353264
doi: 10.5281/zenodo.12926830
62 changes: 33 additions & 29 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,6 @@ To view the log output, use the command

### Formatting

We use [pre-commit](https://github.com/pre-commit/pre-commit) to make sure the coding style is enforced.
You first need to install pre-commit and the corresponding git commit hooks by running the following commands:

```bash
python3 -m pip install pre-commit
pre-commit install
```

After that you can make sure your code satisfies the coding style by running the following command:

```bash
pre-commit run --all-files
```

These checks will also run automatically before every commit.

### Formatting

We use [autopep8](https://github.com/hhatto/autopep8) with a 120 character line length to format our code.
Before submitting a pull request, please run

Expand All @@ -109,24 +91,46 @@ There are cases where one or the other arrangement of, e.g., function arguments
Then we like the flexibility to either put all arguments on separate lines or only put the lengthy event handler
on a second line and leave the other arguments as they are.

### Imports
### Linting

We use [ruff](https://docs.astral.sh/ruff/) to automatically sort imports:
We use [pre-commit](https://github.com/pre-commit/pre-commit) to make sure the coding style is enforced.
You first need to install pre-commit and the corresponding git commit hooks by running the following commands:

```bash
ruff check . --fix
python3 -m pip install pre-commit
pre-commit install
```

### Single vs Double Quotes

Regarding single or double quotes: [PEP 8](https://peps.python.org/pep-0008/) doesn't give any recommendation, so we simply chose single quotes and sticked with it.
On qwerty keyboards it's a bit easier to type, is visually less cluttered, and it works well for strings containing double quotes from the English language.
After that you can make sure your code satisfies the coding style by running the following command:

### F-Strings
```bash
pre-commit run --all-files
```

We use f-strings where ever possible because they are generally more readable - once you get used to them.
There are only a few places in the code base where performance really matters and f-strings might not be the best choice.
These places should be marked with a `# NOTE: ...` comment when diverging from f-string usage.
> [!TIP]
> The command may fail with
>
> > RuntimeError: failed to find interpreter for Builtin discover of python_spec='python3.8'
>
> You will need to install Python 3.8 and make sure it is available in your `PATH`.
These checks will also run automatically before every commit:

- Run `ruff check . --fix` to check the code and sort imports.
- Remove trailing whitespace.
- Fix end of files.
- Enforce single quotes.

> [!NOTE]
>
> **Regarding single or double quotes:** > [PEP 8](https://peps.python.org/pep-0008/) doesn't give any recommendation, so we simply chose single quotes and sticked with it.
> On qwerty keyboards it's a bit easier to type, is visually less cluttered, and it works well for strings containing double quotes from the English language.
> [!NOTE]
>
> **We use f-strings** where ever possible because they are generally more readable - once you get used to them.
> There are only a few places in the code base where performance really matters and f-strings might not be the best choice.
> These places should be marked with a `# NOTE: ...` comment when diverging from f-string usage.
## Running tests

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ Note: NiceGUI will automatically reload the page when you modify the code.
## Documentation and Examples

The documentation is hosted at [https://nicegui.io/documentation](https://nicegui.io/documentation) and provides plenty of live demos.
The whole content of [https://nicegui.io](https://nicegui.io) is [implemented with NiceGUI itself](https://github.com/zauberzeug/nicegui/blob/main/main.py).
The whole content of [https://nicegui.io](https://nicegui.io) is [implemented with NiceGUI itself](https://github.com/zauberzeug/nicegui/blob/main/main.py)
and can be started locally with `docker run -p 8080:8080 zauberzeug/nicegui` or by executing `main.py` from this repository.

You may also have a look at our [in-depth examples](https://github.com/zauberzeug/nicegui/tree/main/examples) of what you can do with NiceGUI.
In our wiki we have a list of great [NiceGUI projects from the community](https://github.com/zauberzeug/nicegui/wiki#community-projects), a section with [Tutorials](https://github.com/zauberzeug/nicegui/wiki#tutorials), a growing list of [FAQs](https://github.com/zauberzeug/nicegui/wiki/FAQs) and [some strategies for using ChatGPT / LLMs to get help about NiceGUI](https://github.com/zauberzeug/nicegui/wiki#chatgpt).
Expand Down
Empty file.
14 changes: 9 additions & 5 deletions examples/authentication/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from fastapi.responses import RedirectResponse
from starlette.middleware.base import BaseHTTPMiddleware

from nicegui import Client, app, ui
from nicegui import app, ui

# in reality users passwords would obviously need to be hashed
passwords = {'user1': 'pass1', 'user2': 'pass2'}
Expand All @@ -27,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 Client.page_routes.values() and request.url.path not in unrestricted_page_routes:
if not request.url.path.startswith('/_nicegui') 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 All @@ -38,10 +38,13 @@ async def dispatch(self, request: Request, call_next):

@ui.page('/')
def main_page() -> None:
def logout() -> None:
app.storage.user.clear()
ui.navigate.to('/login')

with ui.column().classes('absolute-center items-center'):
ui.label(f'Hello {app.storage.user["username"]}!').classes('text-2xl')
ui.button(on_click=lambda: (app.storage.user.clear(), ui.navigate.to('/login')), icon='logout') \
.props('outline round')
ui.button(on_click=logout, icon='logout').props('outline round')


@ui.page('/subpage')
Expand All @@ -67,4 +70,5 @@ def try_login() -> None: # local function to avoid passing username and passwor
return None


ui.run(storage_secret='THIS_NEEDS_TO_BE_CHANGED')
if __name__ in {'__main__', '__mp_main__'}:
ui.run(storage_secret='THIS_NEEDS_TO_BE_CHANGED')
37 changes: 37 additions & 0 deletions examples/authentication/test_authentication.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import pytest

from nicegui.testing import User

from . import main

# pylint: disable=missing-function-docstring

pytest_plugins = ['nicegui.testing.plugin']


@pytest.mark.module_under_test(main)
async def test_login_logoff(user: User) -> None:
await user.open('/')
user.find('Username').type('user1')
user.find('Password').type('pass1')
user.find('Log in').click()
await user.should_see('Hello user1!')
user.find('logout').click()
await user.should_see('Log in')


@pytest.mark.module_under_test(main)
async def test_wrong_password(user: User) -> None:
await user.open('/')
user.find('Username').type('user1')
user.find('Password').type('wrong').trigger('keydown.enter')
await user.should_see('Wrong username or password')


@pytest.mark.module_under_test(main)
async def test_subpage_access(user: User) -> None:
await user.open('/subpage')
await user.should_see('Log in')
user.find('Username').type('user1')
user.find('Password').type('pass1').trigger('keydown.enter')
await user.should_see('This is a sub page.')
Empty file added examples/chat_app/__init__.py
Empty file.
11 changes: 8 additions & 3 deletions examples/chat_app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@

@ui.refreshable
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)
if messages:
for user_id, avatar, text, stamp in messages:
ui.chat_message(text=text, stamp=stamp, avatar=avatar, sent=own_id == user_id)
else:
ui.label('No messages yet').classes('mx-auto my-36')
ui.run_javascript('window.scrollTo(0, document.body.scrollHeight)')


Expand Down Expand Up @@ -40,4 +43,6 @@ def send() -> None:
with ui.column().classes('w-full max-w-2xl mx-auto items-stretch'):
chat_messages(user_id)

ui.run()

if __name__ in {'__main__', '__mp_main__'}:
ui.run()
40 changes: 40 additions & 0 deletions examples/chat_app/test_chat_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from typing import Callable

import pytest

from nicegui import ui
from nicegui.testing import User

from . import main

pytest_plugins = ['nicegui.testing.plugin']


@pytest.mark.module_under_test(main)
async def test_basic_startup_appearance(user: User) -> None:
"""Test basic appearance of the chat app."""
await user.open('/')
await user.should_see('simple chat app')
await user.should_see('https://robohash.org/')
await user.should_see('message')
await user.should_see('No messages yet')


@pytest.mark.module_under_test(main)
async def test_sending_messages(create_user: Callable[[], User]) -> None:
"""Test sending messages from two different screens."""
userA = create_user()
userB = create_user()

await userA.open('/')
userA.find(ui.input).type('Hello from screen A!').trigger('keydown.enter')
await userA.should_see('Hello from screen A!')
await userA.should_see('message')

await userB.open('/')
await userB.should_see('Hello from screen A!')
userB.find(ui.input).type('Hello from screen B!').trigger('keydown.enter')
await userB.should_see('message')

await userA.should_see('Hello from screen A!')
await userA.should_see('Hello from screen B!')
2 changes: 0 additions & 2 deletions examples/pytest/conftest.py

This file was deleted.

12 changes: 0 additions & 12 deletions examples/pytest/main.py

This file was deleted.

7 changes: 0 additions & 7 deletions examples/pytest/requirements.txt

This file was deleted.

17 changes: 0 additions & 17 deletions examples/pytest/test_main_page.py

This file was deleted.

File renamed without changes.
Empty file.
21 changes: 21 additions & 0 deletions examples/pytests/app/startup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from nicegui import Client, ui

# pylint: disable=missing-function-docstring


def startup() -> None:
@ui.page('/')
def main_page() -> None:
ui.markdown('Try running `pytest` on this project!')
ui.button('Click me', on_click=lambda: ui.notify('Button clicked!'))
ui.link('go to subpage', '/subpage')

@ui.page('/subpage')
def sub_page() -> None:
ui.markdown('This is a subpage')

@ui.page('/with_connected')
async def with_connected(client: Client) -> None:
ui.markdown('This is an async connection demo')
await client.connected()
ui.markdown('Connected!')
8 changes: 8 additions & 0 deletions examples/pytests/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env python3
from app.startup import startup

from nicegui import app, ui

app.on_startup(startup)

ui.run()
2 changes: 2 additions & 0 deletions examples/pytests/pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[pytest]
asyncio_mode = auto
3 changes: 3 additions & 0 deletions examples/pytests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
nicegui
pytest-asyncio
pytest-selenium
Empty file.
20 changes: 20 additions & 0 deletions examples/pytests/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import Generator

import pytest
from app.startup import startup

from nicegui.testing import Screen, User

pytest_plugins = ['nicegui.testing.plugin']


@pytest.fixture
def user(user: User) -> Generator[User, None, None]:
startup()
yield user


@pytest.fixture
def screen(screen: Screen) -> Generator[Screen, None, None]:
startup()
yield screen
31 changes: 31 additions & 0 deletions examples/pytests/tests/test_with_screen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from nicegui.testing import Screen

# pylint: disable=missing-function-docstring


def test_markdown_message(screen: Screen) -> None:
screen.open('/')
screen.should_contain('Try running')


def test_button_click(screen: Screen) -> None:
screen.open('/')
screen.click('Click me')
screen.should_contain('Button clicked!')


def test_sub_page(screen: Screen) -> None:
screen.open('/subpage')
screen.should_contain('This is a subpage')


def test_with_connected(screen: Screen) -> None:
screen.open('/with_connected')
screen.should_contain('This is an async connection demo')
screen.should_contain('Connected!')


def test_navigation(screen: Screen) -> None:
screen.open('/')
screen.click('go to subpage')
screen.should_contain('This is a subpage')
Loading

0 comments on commit 4c59444

Please sign in to comment.