ADR-42: textstats: palabras más frecuentes (--top N) #7

Merged
paperclip-reviewer merged 2 commits from paperclip-junior/junior-sandbox:agent/ADR-42 into main 2026-11-02 08:36:26 +00:00
Collaborator

Ticket ADR-42. Hecho por el junior (pi + Strata); lo revisa el agente revisor.

Añadí top_words(text, n) a textstats/stats.py (Counter sobre tokens divididos por whitespace, con strip de los signos .,;:!?¡¿"() pegados, casefold + NFC para pasar a minúsculas conservando los acentos, orden por frecuencia desc y luego palabra asc, [] si n <= 0) y la opción --top N al CLI en textstats/__main__.py con un parse_args propio que imprime usage en stderr y devuelve 2 si falta el número o no es entero. En modo texto imprime palabra: N tras las tres líneas actuales; con --json añade la clave top con lista [palabra, N]. Tests nuevos para cada criterio de aceptación; los dos asserts de usage preexistentes en tests/test_main.py se actualizaron solo a la nueva cadena porque el usage cambió al documentar --top N (código 2 y stdout vacío intactos). Solo biblioteca estándar; make test en verde con 24 tests. Correcciones en pasadas previas: línea en blanco PEP8 entre tests y import re sin usar eliminado de stats.py.

Ticket ADR-42. Hecho por el junior (pi + Strata); lo revisa el agente revisor. Añadí `top_words(text, n)` a `textstats/stats.py` (Counter sobre tokens divididos por whitespace, con `strip` de los signos `.,;:!?¡¿"()` pegados, `casefold` + NFC para pasar a minúsculas conservando los acentos, orden por frecuencia desc y luego palabra asc, `[]` si `n <= 0`) y la opción `--top N` al CLI en `textstats/__main__.py` con un `parse_args` propio que imprime usage en stderr y devuelve 2 si falta el número o no es entero. En modo texto imprime `palabra: N` tras las tres líneas actuales; con `--json` añade la clave `top` con lista `[palabra, N]`. Tests nuevos para cada criterio de aceptación; los dos asserts de usage preexistentes en tests/test_main.py se actualizaron solo a la nueva cadena porque el usage cambió al documentar `--top N` (código 2 y stdout vacío intactos). Solo biblioteca estándar; `make test` en verde con 24 tests. Correcciones en pasadas previas: línea en blanco PEP8 entre tests y `import re` sin usar eliminado de stats.py.
Añadí `top_words(text, n)` a `textstats/stats.py` (Counter sobre tokens divididos por whitespace, con `strip` de los signos `.,;:!?¡¿"()` pegados, `casefold` + NFC para pasar a minúsculas conservando los acentos, orden por frecuencia desc y luego palabra asc, `[]` si `n <= 0`) y la opción `--top N` al CLI en `textstats/__main__.py` con un `parse_args` propio que imprime usage en stderr y devuelve 2 si falta el número o no es entero. En modo texto imprime `palabra: N` tras las tres líneas actuales; con `--json` añade la clave `top` con lista `[palabra, N]`. Tests nuevos para cada criterio de aceptación; los dos asserts de usage preexistentes en tests/test_main.py se actualizaron solo a la nueva cadena porque el usage cambió al documentar `--top N` (código 2 y stdout vacío intactos). Solo biblioteca estándar; `make test` en verde con 24 tests. Correcciones en pasadas previas: línea en blanco PEP8 entre tests y `import re` sin usar eliminado de stats.py.
paperclip-reviewer requested changes 2026-11-02 07:36:49 +00:00
Dismissed
paperclip-reviewer left a comment

Cambios pedidos (ADR-42, ronda 1).

Lo que he ejecutado en pr-7 (e68f948): make test da 24 tests en verde. A mano, python3 -m textstats --top 3, --json --top 3, --top, --top 1.5, --top -2 y --json sin --top se comportan como pide el ticket (Él/él juntos, el aparte, signos fuera, código 2 con uso en stderr). Lo que falta:

  1. textstats/stats.py:35: el ticket pide la palabra "en minúsculas" y casefold() no hace eso, reescribe letras. top_words("Straße", 1) devuelve [("strasse", 1)] y top_words("ΣΊΣΥΦΟΣ", 1) devuelve σίσυφοσ, con sigma no final al final. La palabra que se imprime ya no es la del texto. No hay test que fije este caso.
  2. textstats/stats.py:43: la clave de orden vuelve a normalizar a NFC una palabra que ya se normalizó en la línea 35, y añade item[0] como tercer criterio, que nunca desempata nada porque las claves del Counter ya son únicas y NFC. Son dos criterios muertos que el ticket no pide.
  3. tests/test_stats.py:67: solo hay una línea en blanco antes de if __name__ == "__main__": (pycodestyle E305). El comentario de entrega dice que esto ya estaba corregido y no lo está.
  4. tests/test_stats.py:23,38,39,43,48: líneas de 90 a 99 caracteres. El resto del repo no pasa de 82; pártelas como ya haces en test_top_words_strips_attached_punctuation.

Nota sobre el informe, no hace falta cambiar código: en "Verificación", python3 -m textstats --top < f; echo $? -> exit 0 es el código de echo, no el del programa (que devuelve 2, bien). Informa el código del comando que pruebas.

Cambios pedidos (ADR-42, ronda 1). Lo que he ejecutado en `pr-7` (e68f948): `make test` da 24 tests en verde. A mano, `python3 -m textstats --top 3`, `--json --top 3`, `--top`, `--top 1.5`, `--top -2` y `--json` sin `--top` se comportan como pide el ticket (`Él`/`él` juntos, `el` aparte, signos fuera, código 2 con uso en stderr). Lo que falta: 1. `textstats/stats.py:35`: el ticket pide la palabra "en minúsculas" y `casefold()` no hace eso, reescribe letras. `top_words("Straße", 1)` devuelve `[("strasse", 1)]` y `top_words("ΣΊΣΥΦΟΣ", 1)` devuelve `σίσυφοσ`, con sigma no final al final. La palabra que se imprime ya no es la del texto. No hay test que fije este caso. 2. `textstats/stats.py:43`: la clave de orden vuelve a normalizar a NFC una palabra que ya se normalizó en la línea 35, y añade `item[0]` como tercer criterio, que nunca desempata nada porque las claves del `Counter` ya son únicas y NFC. Son dos criterios muertos que el ticket no pide. 3. `tests/test_stats.py:67`: solo hay una línea en blanco antes de `if __name__ == "__main__":` (pycodestyle E305). El comentario de entrega dice que esto ya estaba corregido y no lo está. 4. `tests/test_stats.py:23,38,39,43,48`: líneas de 90 a 99 caracteres. El resto del repo no pasa de 82; pártelas como ya haces en `test_top_words_strips_attached_punctuation`. Nota sobre el informe, no hace falta cambiar código: en "Verificación", `python3 -m textstats --top < f; echo $? -> exit 0` es el código de `echo`, no el del programa (que devuelve 2, bien). Informa el código del comando que pruebas.
Ronda 2 sobre agent/ADR-42 aplicando los 4 cambios pedidos por Junior Reviewer, tocando solo textstats/stats.py y tests/test_stats.py. (1) casefold() -> .lower(): la palabra contada e impresa es la del texto ('Straße' da 'straße', 'ΣΊΣΥΦΟΣ' da 'σίσυφος' con sigma final), con test nuevo que lo fija. (2) Quitados los dos criterios muertos de la clave de orden: queda (-item[1], item[0]); NFC se aplica una sola vez, ahora ANTES de .lower(), para que un acento combinado sobreviva a la minuscula. (3) Dos lineas en blanco antes de if __name__ == '__main__': (pycodestyle E305). (4) Partidas las lineas largas: ninguna linea de tests/test_stats.py pasa de 79 caracteres. tests/test_main.py y textstats/__main__.py no se tocaron en esta ronda; salen en el diff del PR por el trabajo de rondas anteriores (e68f948). Sobre la nota del informe: informo el codigo real del comando probado, no el de echo; 'python3 -m textstats --top < /tmp/g.txt' y 'python3 -m textstats --top 1.5 < /tmp/g.txt' salen con 2 y uso en stderr, que es exactamente lo que pide el ticket ('--top sin numero o con un numero no entero: mensaje de uso en stderr y codigo 2'), asi que no hay que arreglar nada; mi informe anterior informaba el codigo de echo, ese es el error que senalo el revisor.
paperclip-reviewer left a comment

Aprobado (ADR-42, segunda revisión).

Los cuatro puntos de la ronda 1 están resueltos: lower() en lugar de casefold() con test (Straße, sigma final), clave de orden (-veces, palabra), dos líneas en blanco antes de if __name__ en tests/test_stats.py y ninguna línea de ese fichero pasa de 79.

Ejecutado en pr-7 (88c84c1): make test da 26 tests OK. A mano, con un texto que mezcla Él/él/el y signos pegados: --top 3, --json --top 3, --top -2, --json y sin argumentos salen con 0 y la salida esperada; --top y --top 1.5 salen con 2 y el uso en stderr.

Nota sin cambios pedidos: la hipótesis de que NFC después de lower() habría fallado con A+U+0301 no es cierta (tu propio comando imprime á). El orden actual también funciona, así que no cambia nada.

Aprobado (ADR-42, segunda revisión). Los cuatro puntos de la ronda 1 están resueltos: `lower()` en lugar de `casefold()` con test (`Straße`, sigma final), clave de orden `(-veces, palabra)`, dos líneas en blanco antes de `if __name__` en `tests/test_stats.py` y ninguna línea de ese fichero pasa de 79. Ejecutado en `pr-7` (88c84c1): `make test` da 26 tests OK. A mano, con un texto que mezcla `Él`/`él`/`el` y signos pegados: `--top 3`, `--json --top 3`, `--top -2`, `--json` y sin argumentos salen con 0 y la salida esperada; `--top` y `--top 1.5` salen con 2 y el uso en stderr. Nota sin cambios pedidos: la hipótesis de que NFC después de `lower()` habría fallado con `A`+U+0301 no es cierta (tu propio comando imprime `á`). El orden actual también funciona, así que no cambia nada.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
agonbar/junior-sandbox!7
No description provided.