feat: funciones Python infra y tipos Python (core, datascience, infra)

Infra: cache_to_file, cache_to_sqlite, http_download_file, http_get_json,
http_post_json, read_file_with_encoding, safe_extract_zip, scan_directory,
setup_logger, normalize_zip_filenames.
Tipos: 30+ tipos core (agent_action, context, task, message, parse_result...),
6 tipos datascience (entity_candidate, extraction_result...), 2 tipos infra.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 17:11:43 +02:00
parent 63a9cb5273
commit 9fd0ca9cac
110 changed files with 5714 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
---
name: cache_to_sqlite
kind: function
lang: py
domain: infra
version: "1.0.0"
purity: impure
signature: "def cache_to_sqlite(db_path: str, namespace: str = 'default') -> CacheStore"
description: "Cache key-value persistido en SQLite con TTL y lazy eviction. Cada namespace es un espacio logico dentro de la misma BD. Keys son strings, values se serializan con JSON. TTL en segundos, 0 = sin expiracion. Thread-safe mediante mutex."
tags: [cache, sqlite, persistence, ttl, memoize, key-value]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["sqlite3", "json", "time", "threading"]
tested: true
tests:
- "Set y get basico"
- "TTL expirado → None"
- "TTL 0 → nunca expira"
- "get_or_set con factory que solo se llama en miss"
- "Namespaces independientes"
- "Clear elimina solo el namespace"
- "Stats contadores correctos"
- "Concurrencia (threading basico)"
test_file_path: "python/functions/infra/cache_to_sqlite_test.py"
file_path: "python/functions/infra/cache_to_sqlite.py"
---
## Ejemplo
```python
from infra.cache_to_sqlite import cache_to_sqlite
store = cache_to_sqlite("my_cache.db", namespace="llm")
# Almacenar con TTL de 1 hora
store.set("prompt:explain_x", "explanation...", ttl=3600)
# Recuperar (None si miss o expirado)
val = store.get("prompt:explain_x")
# Factory pattern: solo computa si no esta en cache
result = store.get_or_set(
"prompt:explain_y",
factory=lambda: call_llm("explain y"),
ttl=3600,
)
# Estadisticas
print(store.stats()) # {"hits": 2, "misses": 1, "size": 5}
```
## Notas
La eviction de entradas expiradas es lazy: se ejecuta en cada llamada a `get` o `stats`, no en background. El schema SQLite usa `(namespace, key)` como PRIMARY KEY para garantizar upserts atomicos. Usa WAL mode para mejor concurrencia de lecturas. Cada thread mantiene su propia conexion SQLite (thread-local), sincronizada via `threading.Lock` para escrituras.