Initial commit: MUD client v0.2
This commit is contained in:
commit
0030fd7d82
26 files changed
+4421
No files matched your search
@@ -0,0 +1,174 @@
|
||||
# Sviluppo
|
||||
|
||||
Setup locale, pytest, ruff, e come estendere il client.
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
git clone https://192.168.0.183:8085/truetype/progetto2.git
|
||||
cd progetto2
|
||||
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
Lo sviluppo quotidiano è Python puro; nessun build system esterno
|
||||
(setuptools è trasparente via `pyproject.toml`).
|
||||
|
||||
---
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
pytest # 66+ test (telnet + ansi + deadsouls + mapper + logger)
|
||||
pytest tests/test_logger.py -v # solo il logger (più verboso)
|
||||
pytest -k "test_rolling_parser" # filtrato per nome
|
||||
pytest --tb=short # traceback corti
|
||||
```
|
||||
|
||||
I test usano `pytest.ini_options = ["-q"]` di default in `pyproject.toml`.
|
||||
|
||||
### Cosa è coperto
|
||||
|
||||
| File | Copre |
|
||||
| --- | --- |
|
||||
| `test_ansi.py` | stripper ANSI + `visible_len` |
|
||||
| `test_telnet.py` | IACParser (state machine completa) + TelnetConnection (mock asyncio) |
|
||||
| `test_deadsouls.py` | `parse_exits` + `RollingRoomParser` scenario multi‑chunk |
|
||||
| `test_mapper.py` | `Mapper.visit`, link, layout BFS, orphan placement, render |
|
||||
| `test_logger.py` | EventLogger round‑trip JSONL, MD rendering per ogni `kind`, redazione password, idempotenza `close()`, lone‑ESC safety |
|
||||
|
||||
### Cosa *non* è coperto
|
||||
|
||||
- `cli.py` end‑to‑end (richiede telnet server; il vero test è una
|
||||
smoke run contro il docker locale di Dead Souls).
|
||||
- `mapper._render_vertical_row` (casi degeneri con celle non
|
||||
continue; non aggiunti perché non osservati in pratica).
|
||||
- Re‑entrata del logger in un worker thread (lock difensivo è
|
||||
documentato ma non testato).
|
||||
|
||||
---
|
||||
|
||||
## Lint
|
||||
|
||||
```bash
|
||||
ruff check src tests
|
||||
ruff format src tests
|
||||
```
|
||||
|
||||
Config in `pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py310"
|
||||
```
|
||||
|
||||
(Aggiungi regole strict `select = ["E", "F", "I", "B", "UP"]` se
|
||||
vuoi enforcement.)
|
||||
|
||||
---
|
||||
|
||||
## Smoke test end‑to‑end
|
||||
|
||||
Dead Souls docker su `localhost:6666`:
|
||||
|
||||
```bash
|
||||
# 2 secondi, log JSONL + MD
|
||||
LOGJSON=$(mktemp /tmp/mud-json.XXXXXX.jsonl)
|
||||
LOGMD=$(mktemp /tmp/mud-md.XXXXXX.md)
|
||||
timeout 2 python -m progetto2 --host localhost --port 6666 \
|
||||
--log-json "$LOGJSON" --log-md "$LOGMD" </dev/null >/dev/null 2>&1 || true
|
||||
wc -l "$LOGJSON" "$LOGMD"
|
||||
head -3 "$LOGJSON"
|
||||
head -8 "$LOGMD"
|
||||
```
|
||||
|
||||
Aspettative: almeno 2‑3 righe JSONL (session_start, text, session_end)
|
||||
e un header MD con `host/port/user`.
|
||||
|
||||
---
|
||||
|
||||
## Come aggiungere un modulo
|
||||
|
||||
Esempio: nuovo modulo `directions.py` che assorbe `EXIT_ALIASES` da
|
||||
`deadsouls.py`. Procedura:
|
||||
|
||||
1. Crea `src/progetto2/directions.py` con le costanti e `normalize_exits()`.
|
||||
2. Aggiorna `deadsouls.py` → re‑import da `directions` per back‑compat.
|
||||
3. Aggiorna `gmcp.py`, `mapper.py`, `cli.py` → import da `directions`.
|
||||
4. Scrivi `tests/test_directions.py`.
|
||||
5. Aggiorna questo file (`docs/development.md`) e `docs/modules.md`.
|
||||
6. `pytest` + `ruff check`.
|
||||
|
||||
### Principi
|
||||
|
||||
- **Foglia pura sopra orchestratore.** Solo `cli.py` può dipendere da
|
||||
più moduli. Mai il contrario.
|
||||
- **No mutazione cross‑module.** Ogni modulo possiede il suo stato.
|
||||
- **Mai dipendere dal payload GMCP da mapper o deadsouls.** Sono
|
||||
moduli di testo puro.
|
||||
- **Mai import `cli` da moduli bassi.** Solo `cli` sa di `prompt_toolkit`.
|
||||
|
||||
---
|
||||
|
||||
## Debugging tipico
|
||||
|
||||
| Sintomo | Tool |
|
||||
| --- | --- |
|
||||
| IAC parser perso un byte | `pytest tests/test_telnet.py -v` + aggiungere print in `_byte()` |
|
||||
| GMCP module non riconosciuto | leggere `gmcp.parse_gmcp` con `data=b"..."` in REPL |
|
||||
| Stanze non rilevate senza GMCP | stampare `state.parser._buf` dopo feed_text |
|
||||
| Mapper collassa in `[mappa troppo larga]` | abbassare `max_cols`/`max_rows` in `render(...)` |
|
||||
| Stanza GMCP arriva ma render non aggiorna | `state.mapper.current_room` punta ancora al vecchio? |
|
||||
| Password finisce nel log | grep `--log-md` per `hunter2`/`***` ratio |
|
||||
| Sessione hung dopo quit | `conn.close()` chiamato? `finally` cleanup? |
|
||||
|
||||
---
|
||||
|
||||
## Aggiungere un nuovo comando slash
|
||||
|
||||
1. In `cli.py:_handle_local_command`, aggiungi un ramo `elif cmd == "foo":`.
|
||||
2. Se modifica stato → metti la logica prima del `if state.logger is not None: state.logger.local_cmd(...)`.
|
||||
3. Se inoltra al MUD → usa `await conn.send_line("foo")`.
|
||||
4. Aggiungi voce nella tabella di `docs/usage.md` e `_print_help()`.
|
||||
5. Test: aggiungi in `tests/test_cli.py` (futuro; ancora non esiste).
|
||||
|
||||
---
|
||||
|
||||
## Versioning
|
||||
|
||||
`__version__` in `__init__.py` (`0.1.0` in v0.2). Bump:
|
||||
|
||||
- **patch** (0.1.x): bug fix, no nuovi flag.
|
||||
- **minor** (0.x.0): nuovi flag, nuove feature senza break della CLI.
|
||||
- **major** (x.0.0): break di `--log-*` schema eventi o rename simboli
|
||||
pubblici dei moduli.
|
||||
|
||||
---
|
||||
|
||||
## CI minima (Gitea Actions, opzionale)
|
||||
|
||||
Esempio `.gitea/workflows/ci.yml`:
|
||||
|
||||
```yaml
|
||||
name: CI
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- run: python -m pip install -e ".[dev]"
|
||||
- run: pytest
|
||||
- run: ruff check src tests
|
||||
```
|
||||
|
||||
Adatta ai vincoli del tuo runner Gitea (alcuni runner non hanno
|
||||
`actions/setup-python@v5`; pinning a versioni disponibili è tipico).
|
||||
Reference in new issue
Block a user