feat(infra): grupo claude-fleet — FleetView TUI + orquestacion de Claudes
Sistema FleetView para centralizar la flota de procesos Claude Code vivos en una sola ventana kitty + tmux (socket aislado -L fleet) con un panel TUI: - list_claude_fleet (+ tipo claude_fleet): escanea ~/.claude/sessions + goals + runtime, valida procesos vivos (anti-PID-reciclado), join por sessionId. - list_resumable_claudes (+ tipo resumable_claude): sesiones cerradas reanudables. - wrappers tmux: tmux_new_claude_window (con --resume), tmux_swap_window_into_console (preserva ancho del sidebar), tmux_map_claude_panes. - launch_kittyclaude: comando entrypoint; instala atajos alt+flechas/enter/n/0/k/r, mouse on, remain-on-exit off; fija el ancho del sidebar con hooks. - docs/capabilities/claude-fleet.md + entrada en el INDEX. Incluye ademas funciones datascience en progreso (excel/duckdb/postgres) y ajustes varios de docs e infra de otra sesion, agrupados aqui para no perderlos. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
"""Tests para add_xlsx_chart.
|
||||
|
||||
Modulos importados por path directo (sin tocar __init__.py). write_xlsx_sheets
|
||||
escribe los datos; add_xlsx_chart les anade un grafico; reabrimos el libro y
|
||||
verificamos que ws._charts contiene el chart.
|
||||
"""
|
||||
|
||||
import importlib.util
|
||||
import os
|
||||
|
||||
from openpyxl import load_workbook
|
||||
|
||||
_HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def _load(name):
|
||||
spec = importlib.util.spec_from_file_location(name, os.path.join(_HERE, f"{name}.py"))
|
||||
mod = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(mod)
|
||||
return mod
|
||||
|
||||
|
||||
add_xlsx_chart = _load("add_xlsx_chart").add_xlsx_chart
|
||||
write_xlsx_sheets = _load("write_xlsx_sheets").write_xlsx_sheets
|
||||
|
||||
|
||||
def _book_with_data(tmp_path):
|
||||
out = str(tmp_path / "chart.xlsx")
|
||||
write_xlsx_sheets(
|
||||
out,
|
||||
{
|
||||
"Ventas": [
|
||||
["Mes", "Unidades"],
|
||||
["Ene", 120],
|
||||
["Feb", 150],
|
||||
["Mar", 90],
|
||||
["Abr", 200],
|
||||
],
|
||||
},
|
||||
)
|
||||
return out
|
||||
|
||||
|
||||
def test_add_bar_chart_reabre_y_verifica(tmp_path):
|
||||
out = _book_with_data(tmp_path)
|
||||
res = add_xlsx_chart(
|
||||
xlsx_path=out,
|
||||
sheet_name="Ventas",
|
||||
chart_type="bar",
|
||||
data_range="B1:B5",
|
||||
cats_range="A2:A5",
|
||||
anchor="D2",
|
||||
title="Unidades por mes",
|
||||
x_title="Mes",
|
||||
y_title="Unidades",
|
||||
)
|
||||
assert res["status"] == "ok"
|
||||
assert res["chart_type"] == "bar"
|
||||
assert res["sheet"] == "Ventas"
|
||||
assert res["anchor"] == "D2"
|
||||
|
||||
wb = load_workbook(out)
|
||||
ws = wb["Ventas"]
|
||||
assert len(ws._charts) == 1
|
||||
|
||||
|
||||
def test_add_line_chart(tmp_path):
|
||||
out = _book_with_data(tmp_path)
|
||||
res = add_xlsx_chart(out, "Ventas", "line", "B1:B5", cats_range="A2:A5")
|
||||
assert res["status"] == "ok"
|
||||
wb = load_workbook(out)
|
||||
assert len(wb["Ventas"]._charts) == 1
|
||||
|
||||
|
||||
def test_add_pie_chart(tmp_path):
|
||||
out = _book_with_data(tmp_path)
|
||||
res = add_xlsx_chart(out, "Ventas", "pie", "B2:B5", cats_range="A2:A5", anchor="D10")
|
||||
assert res["status"] == "ok"
|
||||
wb = load_workbook(out)
|
||||
assert len(wb["Ventas"]._charts) == 1
|
||||
|
||||
|
||||
def test_add_scatter_chart(tmp_path):
|
||||
out = _book_with_data(tmp_path)
|
||||
res = add_xlsx_chart(
|
||||
out, "Ventas", "scatter", data_range="B2:B5", cats_range="A2:A5"
|
||||
)
|
||||
assert res["status"] == "ok"
|
||||
wb = load_workbook(out)
|
||||
assert len(wb["Ventas"]._charts) == 1
|
||||
|
||||
|
||||
def test_dos_charts_en_la_misma_hoja(tmp_path):
|
||||
out = _book_with_data(tmp_path)
|
||||
assert add_xlsx_chart(out, "Ventas", "bar", "B1:B5", "A2:A5", "D2")["status"] == "ok"
|
||||
assert add_xlsx_chart(out, "Ventas", "line", "B1:B5", "A2:A5", "D20")["status"] == "ok"
|
||||
wb = load_workbook(out)
|
||||
assert len(wb["Ventas"]._charts) == 2
|
||||
|
||||
|
||||
def test_chart_type_invalido_devuelve_error(tmp_path):
|
||||
out = _book_with_data(tmp_path)
|
||||
res = add_xlsx_chart(out, "Ventas", "donut", "B1:B5")
|
||||
assert res["status"] == "error"
|
||||
assert "chart_type invalido" in res["error"]
|
||||
|
||||
|
||||
def test_hoja_inexistente_devuelve_error(tmp_path):
|
||||
out = _book_with_data(tmp_path)
|
||||
res = add_xlsx_chart(out, "Fantasma", "bar", "B1:B5")
|
||||
assert res["status"] == "error"
|
||||
assert "no existe" in res["error"]
|
||||
|
||||
|
||||
def test_libro_inexistente_devuelve_error():
|
||||
res = add_xlsx_chart("/tmp/no_existe_seguro_987654.xlsx", "S", "bar", "B1:B5")
|
||||
assert res["status"] == "error"
|
||||
assert "no encontrado" in res["error"]
|
||||
|
||||
|
||||
def test_data_range_invalido_devuelve_error(tmp_path):
|
||||
out = _book_with_data(tmp_path)
|
||||
res = add_xlsx_chart(out, "Ventas", "bar", "rango_basura")
|
||||
assert res["status"] == "error"
|
||||
assert "data_range invalido" in res["error"]
|
||||
|
||||
|
||||
def test_xlsx_path_vacio_devuelve_error():
|
||||
res = add_xlsx_chart("", "S", "bar", "B1:B5")
|
||||
assert res["status"] == "error"
|
||||
Reference in New Issue
Block a user