---
name: duckdb_list_tables
kind: function
lang: py
domain: infra
version: "1.0.0"
purity: impure
signature: "def duckdb_list_tables(db_path: str, base_tables_only: bool = False) -> dict"
description: "Lista las tablas de una base DuckDB abierta en modo solo lectura (duckdb.connect(db_path, read_only=True)), de modo que nunca crea ni modifica la base. La conexion se cierra siempre en try/finally. Consulta information_schema.tables del esquema main y devuelve los nombres ordenados alfabeticamente. Con base_tables_only=True filtra table_type='BASE TABLE', excluyendo las VIEWs (util para perfilar/relacionar solo tablas reales). Devuelve un dict sin lanzar (estilo del grupo duckdb): {status:'ok', tables} en exito y {status:'error', error} en fallo. Es la introspeccion 'que tablas hay' del grupo duckdb; complementa a duckdb_query_readonly_py_infra (lectura de filas) y a duckdb_table_schema_py_infra (schema de una tabla). Depende del paquete duckdb (1.5.2 en python/.venv)."
tags: [duckdb, sql, introspection, readonly, tables]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_py_core"
imports: [duckdb]
params:
  - name: db_path
    desc: "ruta al archivo DuckDB. Debe existir: el modo read_only NO crea la base. Un path inexistente devuelve {status:'error'}."
  - name: base_tables_only
    desc: "si True (default False) filtra table_type='BASE TABLE', excluyendo las VIEWs del esquema main. Util para perfilar/relacionar solo tablas reales (perfilar una VIEW infla el conteo y multiplica relaciones FK falsas)."
output: "dict. En exito: {status:'ok', tables:[str,...]} con los nombres de tabla del esquema main ordenados alfabeticamente. En error (sin lanzar): {status:'error', error:str}."
tested: true
tests:
  - "test_lista_tablas_ordenadas"
  - "test_base_vacia_devuelve_lista_vacia"
  - "test_db_inexistente_devuelve_status_error"
  - "test_base_tables_only_excluye_views"
  - "test_attach_sqlite_materializado_lista_por_information_schema"
test_file_path: "python/functions/infra/duckdb_list_tables_test.py"
file_path: "python/functions/infra/duckdb_list_tables.py"
---

## Ejemplo

```python
import sys
sys.path.insert(0, "python/functions")
import duckdb
from infra.duckdb_list_tables import duckdb_list_tables

# Preparamos una base de ejemplo (en la realidad la creo otro proceso).
db = "/tmp/almacen.duckdb"
con = duckdb.connect(db)
con.execute("CREATE TABLE ventas (id INTEGER)")
con.execute("CREATE TABLE clientes (id INTEGER)")
con.close()

res = duckdb_list_tables(db)
print(res["status"])   # ok
print(res["tables"])   # ['clientes', 'ventas']
```

## Cuando usarla

Cuando necesitas saber que tablas contiene un archivo DuckDB sin abrirlo en
escritura: inventariar una base materializada, decidir que tabla sincronizar a
PostgreSQL, validar que un pipeline de ingesta creo lo esperado, o alimentar un
selector de tablas en una UI. Es el primer paso natural antes de
`duckdb_table_schema_py_infra` (schema de una tabla) o `duckdb_query_readonly_py_infra`
(lectura de filas). El dict de salida es directamente serializable a JSON.

## Gotchas

- Lectura real de un archivo en disco (impura). El modo `read_only=True` exige que
  el archivo **ya exista**: a diferencia del modo escritura, no crea la base. Si
  `db_path` no existe, devuelve `{status:'error', error:...}`.
- DuckDB es single-writer: si otro proceso tiene la base abierta en escritura con
  una version distinta del motor, la apertura read-only puede fallar con error de
  lock. El error se devuelve como `{status:'error', ...}`, no se lanza.
- Solo lista objetos del esquema `main` (el por defecto); tablas de otros esquemas
  no aparecen. Por defecto incluye **vistas** (table_type VIEW) además de las tablas
  base; pasa `base_tables_only=True` para quedarte solo con las `BASE TABLE`.
- Una base recien creada sin tablas devuelve `{status:'ok', tables:[]}` (no es un
  error): lista vacia.
