---
name: cdp_set_file_input
kind: function
lang: py
domain: browser
version: "1.0.0"
purity: impure
signature: "def cdp_set_file_input(selector: str, file_paths, *, port: int = 9222, target_url_substr: str = '', timeout_s: float = 10.0) -> dict"
description: "Asigna uno o varios archivos a un <input type=file> de una pestana de un Chrome con remote debugging, via CDP, SIN abrir el dialogo nativo del sistema operativo. Localiza el target por substring de URL, abre el WebSocket y ejecuta DOM.enable -> DOM.getDocument -> DOM.querySelector(selector) -> DOM.setFileInputFiles con las rutas ABSOLUTAS. Es el unico metodo robusto para subir archivos por CDP: el navegador no permite escribir el value de un file input desde JS (seguridad) y simular drag&drop es fragil; setFileInputFiles inyecta los File y dispara el evento change que la SPA escucha. Base de whatsapp_send_image y de cualquier flujo de subida de archivos sobre el navegador diario sin robar el foco al usuario."
tags: [cdp, browser, automation, upload, file-input, python, navegator]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["json", "os", "urllib.request", "websocket"]
params_schema:
  params:
    - name: selector
      desc: "Selector CSS del <input type=file> destino. Debe resolver a UN elemento (se usa el primer match). El input puede estar oculto (display:none); CDP lo localiza igual."
    - name: file_paths
      desc: "Ruta (str) o lista de rutas a asignar. Se expanden (~) y se convierten a rutas ABSOLUTAS; cada una debe existir en disco o se aborta con ok=False antes de tocar la red."
    - name: port
      desc: "Puerto de remote debugging de Chrome. Default 9222."
    - name: target_url_substr
      desc: "Substring que debe contener la URL del target (pestana). Si vacio, usa el primer target de tipo 'page'."
    - name: timeout_s
      desc: "Timeout en segundos para la conexion WebSocket. Default 10.0."
  output: "dict {ok: bool, error: str, node_id: int (nodeId CDP del input localizado, 0 si no se encontro), selector: str (eco), files: list[str] (rutas absolutas asignadas)}. ok=True solo si el input se localizo y setFileInputFiles no devolvio error. Nunca lanza: errores de archivo/red/conexion/transport se devuelven en 'error' con ok=False."
tested: true
tests: ["test_golden_asigna_archivos_al_input", "test_edge_archivo_inexistente_ok_false_sin_red", "test_edge_selector_no_encontrado_ok_false", "test_error_create_connection_lanza_ok_false"]
test_file_path: "python/functions/browser/cdp_set_file_input_test.py"
file_path: "python/functions/browser/cdp_set_file_input.py"
---

## Ejemplo

```python
import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from browser.cdp_set_file_input import cdp_set_file_input

# Requiere un Chrome lanzado con --remote-debugging-port=9222.
# Adjuntar una imagen al input de subida de una pestana (WhatsApp Web, un formulario, etc).
# El input "vivo" suele exponerse tras pulsar el boton "Adjuntar"/"Subir" (haz el click antes).
res = cdp_set_file_input(
    'input[type="file"][multiple]',
    "/home/enmanuel/ComfyUI/output/item_icon_potion_00001_.png",
    target_url_substr="whatsapp",
)
print(res["ok"], res["node_id"], res["error"])
# -> True 120
```

O directo por CLI: `python3 python/functions/browser/cdp_set_file_input.py 'input[type="file"]' /ruta/abs.png whatsapp`.

## Cuando usarla

Cuando necesites **subir/adjuntar un archivo** a una pestana abierta sin que aparezca el
dialogo nativo de archivos del sistema operativo (que CDP no puede operar). Es la primitiva
de subida sobre la que se construye `whatsapp_send_image_py_browser` y cualquier
automatizacion de formularios con `<input type=file>`. El patron tipico: primero un click
real (`cdp_click_xy_py_browser`) en el boton que expone el input vivo, luego esta funcion
con el selector del input y la ruta absoluta del archivo.

## Gotchas

- **El input debe existir en el DOM al llamar.** Muchas SPAs (WhatsApp Web) solo crean/activan
  el `<input type=file>` "vivo" DESPUES de pulsar el boton de adjuntar. Haz el click real
  primero; si asignas sobre un input persistente/decoy, `setFileInputFiles` puede devolver ok
  pero la SPA no reacciona (no aparece el preview).
- **Rutas ABSOLUTAS obligatorias.** `setFileInputFiles` exige rutas absolutas; la funcion ya
  convierte (`os.path.abspath` + expanduser), pero el archivo debe existir o aborta con ok=False
  antes de abrir la conexion.
- **El selector debe resolver al input correcto.** Si hay varios `<input type=file>` (uno por
  tipo: fotos, documento...), afina el selector (`[multiple]`, `[accept*="image"]`). Si no
  matchea ninguno, devuelve `ok=False` con "no element matches selector".
- **Dispara `change`, no `input`.** `DOM.setFileInputFiles` emite el evento `change` nativo
  (que la mayoria de uploads escuchan). Si una SPA solo escucha otro evento, no bastara.
- Requiere un Chrome lanzado con `--remote-debugging-port=9222` (o el puerto que pases). Sin
  remote debugging, `GET /json` falla y devuelve `ok=False`.
- Nunca lanza: errores de archivo/red/WS/transport se reportan en `error` con `ok=False`.
