# Diálogo de error

> Qué salió mal, dónde y el traceback, con Copiar e Ir al origen. Componente de Pyzed para GUIs de escritorio en Python, con ejemplos y API.

Source: https://albakore.github.io/pyzed/es/library/error-dialog/

:::tip[En pocas palabras]
Una ventana que aparece cuando algo falla, diciendo qué salió mal y dónde, con un botón para copiarlo en un informe de error.
:::

`ui.error_dialog(info, on_close)` muestra un error en un diálogo: su mensaje, dónde pasó, el archivo y la línea de donde viene y el traceback en un editor de solo lectura, donde se puede seleccionar y copiar cualquier parte. Sus botones copian el informe entero, van al origen (`on_go_to`, con el texto `go_to_label`), lo muestran entre los logs (`on_logs`) y cierran. `more` añade una línea que dice cuántos errores más llegaron después. `info` es un `ui.ErrorInfo`; muestra el diálogo con una [Capa de diálogo](https://albakore.github.io/pyzed/es/library/dialog-layer/).

`ui.error_dialog` · Categoría: [Diálogos](https://albakore.github.io/pyzed/es/library/#diálogos) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#error_dialog)

**Código:**

```python
def average(values):
    return sum(values) / len(values)

try:
    average([])
except ZeroDivisionError as err:
    info = ui.ErrorInfo.from_exception(err, where="Totals")

ui.dialog_layer(main_view(), ui.error_dialog(info, on_close, on_go_to=on_go_to, on_logs=on_logs, width=620))
```

:::note[Nuevo]
Este componente se añadió hace poco. Cuéntanos qué tal te funciona en el [gestor de incidencias](https://github.com/albakore/pyzed/issues).
:::

## Cuándo usarlo

- Cuando algo que pidió el usuario falla (guardar, exportar, ejecutar un script) y los detalles importan.
- Desde el botón Detalles de un [Límite de errores](https://albakore.github.io/pyzed/es/library/error-boundary/).
- Para un mensaje corto sin traceback, usa una [Alerta](https://albakore.github.io/pyzed/es/library/alert/) con `kind="error"`.

## Uso

```python
import pyzed as pz
from pyzed import ui

class Notes(pz.App):
    def __init__(self):
        self.error = None

    def save(self):
        try:
            write_notes(self.notes)
        except OSError as err:
            self.error = ui.ErrorInfo.from_exception(err, where="Save")

    def close_error(self):
        self.error = None

    def view(self):
        dialog = ui.error_dialog(self.error, self.close_error) if self.error else None
        return ui.dialog_layer(self.page(), dialog, on_dismiss=self.close_error)
```

## Variantes

:::note[Sobre estas capturas]
Cada captura la graba pyzed mismo, fuera de pantalla a 2x, en One Dark o One Light según el tema de este sitio, y recortada al componente para que se vea a su tamaño real. El puntero pasa por encima, pulsa o escribe en él; un componente que no reacciona al puntero recorre algunos temas. Con movimiento reducido ves el primer fotograma. Abre **Código** bajo una captura para ver el fragmento que la dibuja; los nombres libres como `on_save` son tus propios callbacks.
:::

### Opciones

Sin traceback el diálogo no muestra la caja de código, como con un `ErrorInfo` que construyes tú.

```python
def average(values):
    return sum(values) / len(values)

try:
    average([])
except ZeroDivisionError as err:
    info = ui.ErrorInfo.from_exception(err, where="Totals")

ui.error_dialog(info, on_close, width=480)
```

```python
def average(values):
    return sum(values) / len(values)

try:
    average([])
except ZeroDivisionError as err:
    info = ui.ErrorInfo.from_exception(err, where="Totals")

ui.error_dialog(info, on_close, on_go_to=on_go_to, go_to_label="Open app.py",
                width=480)
```

```python
def average(values):
    return sum(values) / len(values)

try:
    average([])
except ZeroDivisionError as err:
    info = ui.ErrorInfo.from_exception(err, where="Totals")

ui.error_dialog(info, on_close, on_logs=on_logs, width=480)
```

```python
def average(values):
    return sum(values) / len(values)

try:
    average([])
except ZeroDivisionError as err:
    info = ui.ErrorInfo.from_exception(err, where="Totals")

ui.error_dialog(info, on_close, more=2, width=480)
```

**} alt={**

```python
def average(values):
    return sum(values) / len(values)

try:
    average([])
except ZeroDivisionError as err:
    info = ui.ErrorInfo.from_exception(err, where="Totals")

ui.error_dialog(info, on_close, title="The totals could not be computed", width=480)
```

```python
info = ui.ErrorInfo("PermissionError", "[Errno 13] Permission denied: 'notes.md'", where="Save")
ui.error_dialog(info, on_close, width=480)
```

## Eventos

Diálogo de error tiene **3 eventos propios**, en la tabla de abajo. Como todo widget, también tiene los **18 eventos comunes** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), que se conectan con `.on(...)`: mira [Eventos](https://albakore.github.io/pyzed/es/guides/events/) y [Eventos de cada componente](https://albakore.github.io/pyzed/es/library/events/).

| Evento | El handler recibe | Cuándo |
| --- | --- | --- |
| `on_close` | `()` | Botón Cerrar y Escape. |
| `on_go_to` | `()` | Añade el botón de ir al origen (abre el archivo en la línea). |
| `on_logs` | `()` | Añade el botón Ver en Logs. |

**El handler recibe** es lo que Pyzed le pasa a tu función: `()` es nada. Cualquier handler también puede ser un mensaje (un valor que no se puede llamar), que va a `update()`.

### Manejar los eventos

Los mismos eventos escritos de tres formas. **Imperativa**: métodos de la app que cambian `self`. **Declarativa**: los handlers producen mensajes y un único `update()` decide. **Funcional**: una función pura dibuja un estado inmutable y pide cambios con `set_state(...)`. Mira [Imperativo, declarativo y funcional](https://albakore.github.io/pyzed/es/guides/code-styles/).

**Imperativo:**

```python
class Notes(pz.App):
    def __init__(self):
        try:
            open("/no/such/file")
        except OSError as err:
            self.error = ui.ErrorInfo.from_exception(err, where="Open")

    def close(self):                     # on_close: the button and Escape
        self.error = None

    def view(self):
        dialog = ui.error_dialog(self.error, self.close,
                                 on_go_to=lambda: print("go to", self.error.origin),  # adds Go to
                                 on_logs=lambda: print("show logs")) if self.error else None
        return ui.dialog_layer(main_view(), dialog, on_dismiss=self.close)
```

**Declarativo:**

```python
class Notes(pz.App):
    error = ui.ErrorInfo("FileNotFoundError", "No such file: notes.txt")

    def update(self, message):
        match message:
            case "close":
                self.error = None
            case "logs":
                print("show logs")

    def view(self):
        dialog = ui.error_dialog(self.error, "close", on_logs="logs") if self.error else None
        return ui.dialog_layer(main_view(), dialog, on_dismiss="close")
```

**Funcional:**

```python
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    error: object = ui.ErrorInfo("FileNotFoundError", "No such file: notes.txt")

def view(state, set_state):
    close = lambda: set_state(error=None)
    dialog = ui.error_dialog(state.error, close) if state.error else None
    return ui.dialog_layer(main_view(), dialog, on_dismiss=close)
```

## Consejos

:::tip
`on_go_to` no recibe argumentos: toma el archivo y la línea de `info.origin` (un par `(ruta, línea)`, o `None`) y ábrelo ahí. La caja del traceback es un editor de solo lectura, así que se puede seleccionar una sola línea y copiarla, mientras que Copiar el error copia `info.report()`.
:::

## Propiedades y API

### `ui.error_dialog`

```python
error_dialog(
    info,
    on_close,
    *,
    title=None,
    on_go_to=None,
    go_to_label=None,
    on_logs=None,
    more=0,
    width=680,
    theme=None,
)
```

Un diálogo con un error: su mensaje, dónde pasó, el archivo y la línea de los que viene y el traceback en un editor de solo lectura (selecciona y copia cualquier parte), con botones para copiarlo todo, ir al origen, verlo en los logs y cerrar. Muéstralo con `ui.dialog_layer` o `ui.layer`.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `info` | *obligatorio* | Un `ui.ErrorInfo`. |
| `title` | `None` | Título ("Algo salió mal"). |
| `go_to_label` | `None` | Su texto ("Ir al origen"). |
| `more` | `0` | Cuántos errores más llegaron después (una línea lo dice). |
| `width` | `680` | Ancho en píxeles o un tamaño de modal. |
| `theme` | `None` | Tema a usar. |

Eventos: `on_close`, `on_go_to`, `on_logs` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#error_dialog)

## Relacionados

- [Límite de errores](https://albakore.github.io/pyzed/es/library/error-boundary/): Dibuja una parte de la vista, o una tarjeta de error en su lugar cuando falla.
- [Alerta](https://albakore.github.io/pyzed/es/library/alert/): Un mensaje con un botón.
- [Capa de diálogo](https://albakore.github.io/pyzed/es/library/dialog-layer/): Centra un diálogo encima de tu vista con el fondo oscurecido.
- [Modal](https://albakore.github.io/pyzed/es/library/modal/): Una superficie de diálogo con título, contenido y botones al pie.
