DEV Community

Raül Martínez i Peris
Raül Martínez i Peris

Posted on

Python. Project Structure (IV)

Índice:


En los artículos anteriores hemos conseguido tener una aplicación con un archivo .env y su test correspondiente lanzado en local y en la CI de Gitlab.

En este nuevo apartado levantaremos una página web con 'NiceGUI'.

Preparar una nueva rama

Lo primero será verificar en qué rama estamos:

git branch
Enter fullscreen mode Exit fullscreen mode

Si es necesario cambiamos a la rama main y actualizamos su contenido:

git checkout main
git pull
Enter fullscreen mode Exit fullscreen mode

Creamos una nueva rama y nos posicionamos en ella:

git checkout -b 'release/000-nicegui'
Enter fullscreen mode Exit fullscreen mode

Preparar las nuevas bibliotecas

Actualizamos las bibliotecas, agregando a requirements.txt nicegui y sus dependencias:

# --- pyventus ---
pyventus
# --- aiohttp ---
aiohttp
# --- httpx ---
httpx
# --- GUI, escritorio ---
# --- pywebview ---
pywebview
# --- PyQt6 ---
PyQt6
PyQt6-WebEngine
qtpy
# --- framework ---
nicegui
Enter fullscreen mode Exit fullscreen mode

Añadimos a requirements-dev.txt la biblioteca de test para selenium:

# --- Web ---
pytest-selenium
Enter fullscreen mode Exit fullscreen mode

Y para Windows necesitaremos crear un nuevo archivo de dependencias requirements-extra-windows.txt:

# requirements-extra-windows.txt
pywin32
pythonnet
Enter fullscreen mode Exit fullscreen mode

Además, en Windows, deberá instalar WebView2 manualmente. Consulta la página de descarga de Microsoft https://developer.microsoft.com/es-es/microsoft-edge/webview2/?form=MA13LH#download para descargar e instalar la dependencia en Windows.

Instalamos las dependencias:

# Linux
pip install -r requirements.txt -r requirements-dev.txt 
Enter fullscreen mode Exit fullscreen mode
# Windows
pip install -r requirements.txt -r requirements-dev.txt  -r requirements-extra-windows.txt 
Enter fullscreen mode Exit fullscreen mode

Nuevas variables de entorno

Editamos el archivo .env y añadimos las nuevas variables de entorno:

APP_ENV="native"
APP_MODE="dev"

APP_HOST="127.0.0.1"
APP_PORT=8081

DARK_MODE=True
Enter fullscreen mode Exit fullscreen mode

Añadimos un nuevo archivo .env.example que será el ejemplo para que el resto del equipo pueda configurarse su .env localmente:

APP_NAME="la_fragua"
APP_LABEL="La Fragua"

APP_ENV="" # container / native
APP_MODE="" # dev / production

APP_HOST="" # contenedores: 0.0.0.0 / nativo: 127.0.0.1
APP_PORT=8080

DARK_MODE=True
Enter fullscreen mode Exit fullscreen mode

Añadimos al .gitignore lo siguiente:

assets/external/
.web
*.db
Enter fullscreen mode Exit fullscreen mode

Ahora, abre el archivo app/settings/settings.py y añade las nuevas variables.

Además, necesitaremos una nueva variable, pero en este caso no queremos que esté definida en el .env, sino en un nuevo archivo de configuración para datos estáticos de la aplicación.

Para ello, aprovechando que tienes abierto el archivo app/settings/settings.py añade un nuevo import:

from app.settings import config 
Enter fullscreen mode Exit fullscreen mode

Y una nueva variable a continuación de las que ya has agregado:

window_size: tuple[int, int] = config.DEFAULT_WINDOW_SIZE
Enter fullscreen mode Exit fullscreen mode

Ahora crea el nuevo archivo app/settings/config.py:

# app/settings/config.py
DEFAULT_WINDOW_SIZE = (1280, 768)
Enter fullscreen mode Exit fullscreen mode

Como práctica, puedes añadir un par tests con las nuevas variables de entorno.

Preparar el nuevo test

Ahora, revisamos la configuración de los tests. Añadimos el uso de NiceGUI, actualizando tests/conftest.py con lo siguiente:

from nicegui.testing import User
from app.frontend import startup

pytest_plugins = ['nicegui.testing.user_plugin']

@pytest.fixture
def user(user: User) -> User:
    startup()
    return user
Enter fullscreen mode Exit fullscreen mode

Como es habitual, a cada nueva carpeta necesitaremos añadir su correspondiente archivo __init__.py.

Creamos el nuevo test, tests/front/test_frontend.py:

#tests/front/test_frontend.py
from nicegui import ui
from nicegui.testing import User
from app.settings.settings import settings

host = settings.app_host
port = settings.app_port

async def test_frontend_title(user: User) -> None:
    """
    Test básico para verificar que el frontend se levanta y responde.
    """
    await user.open('/')
    await user.should_see(settings.app_label)
Enter fullscreen mode Exit fullscreen mode

Ahora puedes lanzar los tests y comprobarás que tienes en rojo el nuevo test.

Preparar el código

Creamos el archivo app/main.py:

import sys
import multiprocessing
if sys.platform in ('linux', 'darwin'):
    multiprocessing.set_start_method('spawn', force=True)
import os
from nicegui import ui, app
from app.settings.settings import settings
from app.frontend import startup

host = str(settings.app_host)
port = int(settings.app_port)
app_label = settings.app_label

is_running_tests = "--test-mode" in sys.argv or os.environ.get("TEST_MODE") == "1"
is_native = True if settings.app_env == "native" else False

app.on_startup(startup)
ui.run(
    reload=not is_running_tests,
    dark=settings.dark_mode,
    title=app_label,
    host=host,
    port=port,
    show=not is_running_tests,
    native=is_native,
    window_size=settings.window_size
)
Enter fullscreen mode Exit fullscreen mode

Creamos el archivo app/frontend.py:

from nicegui import ui
from app.settings.settings import settings
from app.front.components.sections.application_title import application_title

app_label = settings.app_label

def startup() -> None:
    @ui.page('/')
    def index_page():
        with ui.column().style('width: 1024px; margin-left: auto; margin-right: auto;'):
            application_title(app_label)
Enter fullscreen mode Exit fullscreen mode

Creamos el archivo app/front/components/sections/application-title.py:

from nicegui import ui

def application_title(label):
    title = ui.label(f"{label}")
    return title
Enter fullscreen mode Exit fullscreen mode

Como ves, main se encarga de llamar a startup que contiene la página inicial / que a su vez llamará a sus componentes, siendo el primer componente el título de la aplicación (application_title). Una vez que tenemos el "contenido" ejecutamos ui.run para levantar la web.

Ya podemos lanzar los tests. Deberían pasar en verde.

También podemos levantar la aplicación con:

# Linux
python3 -m app.main
Enter fullscreen mode Exit fullscreen mode
# Windows
python -m app.main
Enter fullscreen mode Exit fullscreen mode

Apuntes

Python no maneja muy bien las dependencias de las dependencias, por ello, para evitarnos problemas, tomamos la iniciativa de incluir las dependencias de las bibliotecas necesarias.

Enlaces

Repositorio del proyecto:

Enlaces de interés:

Siguiente artículo:

Top comments (0)