Parser for DSV swim-meet files (.dsv5 through .dsv8, including .dsv8z) into a typed data schema. Usable as a Python library, as a CLI, and as a FastAPI service whose OpenAPI document exposes the same schema to services in other languages.
Format 6, 7 and 8 are covered in full, transcribed from the official specifications of the Deutscher Schwimm-Verband.
| Format | Valid | State |
|---|---|---|
| 8 | from 01.08.2026 | Complete, specification of 14.03.2026 |
| 7 | 01.01.2023 – 31.12.2026 | Complete, specification of 31.08.2022 |
| 6 | 01.09.2015 – 31.07.2023 | Complete, specification of 01.11.2015 |
| 5 | until 31.12.2015 | Derived from the Format 6 change log |
All four types (Wettkampfdefinitions-, Vereinsmelde-, Vereinsergebnis- and Wettkampfergebnisliste) with every element and attribute. The packed .dsv8z variant is unwrapped transparently.
Checked against nine real EasyWk files in Format 6 and 7, about 26 000 elements, with no errors or warnings. Details in the format reference.
| Tool | Version | Needed for |
|---|---|---|
| uv | — | dependencies, every make target |
| Python | 3.12 | fetched by uv from .python-version |
| Docker + Compose | — | make up, make image |
| pre-commit | — | the formatting hook before a commit (optional) |
As a dependency of another project:
pip install dsv-parser # library + CLI
pip install "dsv-parser[api]" # plus the FastAPI service
uv add dsv-parserEvery GitHub Release is published to PyPI automatically, so the version there tracks the tags in this repository.
To work on the parser itself:
make install # uv sync --extra apiThe api extra adds FastAPI and uvicorn. The parser itself needs only Pydantic, so a library-only consumer can leave the extra out.
make dev # CLI help with every subcommand
make spec # the element table as implemented
make serve # FastAPI on :8000 with reload
make up # the same in Docker
make ps # container status and health
make logs # follow the logs
make down # stop and removefrom dsv_parser import parse_file
result = parse_file("2026-06-13-Berlin-Pr.DSV8")
print(result.document.meet.name, result.document.file_type)
for swim in result.document.individual_results:
print(swim.place, swim.name, swim.time_millis)
for entry in result.diagnostics.entries:
print(entry.render())dsv-parser parse meet.DSV8 -o meet.json # document as JSON
dsv-parser parse meet.DSV8 --summary # header and element counts only
dsv-parser check meet.DSV8 # validate, exit 1 on data loss
dsv-parser spec --json # element table as data| Method | Path | Purpose |
|---|---|---|
POST |
/parse |
Parse a file and return the document |
POST |
/check |
Validate a file without returning the document |
GET |
/spec |
Element table and all code lists |
GET |
/health |
Liveness and the supported format versions |
GET |
/openapi.json |
The schema, for generated clients |
curl -F file=@meet.DSV8 http://localhost:8000/parse
curl -F file=@meet.DSV8 http://localhost:8000/checkA readable upload always returns 200. Content problems come back as diagnostics rather than HTTP errors, since a partially readable file is a normal result. Check clean and diagnostics, not the status code.
The document schema in /openapi.json is the same Pydantic model the library returns. See the HTTP API.
| Variable | Default | Effect |
|---|---|---|
LOG_LEVEL |
INFO |
Log level |
There is nothing else. The service holds no state and can be mounted into another app with app.include_router(dsv_parser.api.router).
The attribute layouts live as data in dsv_parser/spec/elements.py, one entry per element, with versions= and file_types= wherever the four format versions or the four list kinds differ. For example, WETTKAMPF has no best-list attribute in a Vereinsmeldeliste, which moves the two qualification attributes one position forward. In the table that is a single file_types= on one attribute.
flowchart LR
A["bytes<br/>.dsv · .dsv8z"] -->|decoding| B["text"]
B -->|lexer| C["element lines"]
C -->|binder| D["element models"]
D -->|parser| E["DsvDocument"]
T[("spec table<br/>spec/elements.py")] -.->|layout| C
T -.->|layout| D
C -.-> G(["diagnostics"])
D -.-> G
E -.-> G
More in the architecture notes.
make help # every target
make test # unit tests, offline, no coverage gate
make test-it # full run incl. integration and coverage
make lint # ruff check
make format # ruff: import order and formatting
make format-check # the same, read-only
make typecheck # mypy
make audit # pip-audit
make image # build the runtime image
make clean # remove caches and the venv- Architecture — pipeline, element table, decisions
- Format reference — the format and the version differences
- Data schema — how the document is laid out
- HTTP API — endpoints, payloads, client generation
- CLI — subcommands, flags, exit codes
- Extending — adding elements, versions and code lists
MIT — use it, change it, ship it, commercially or not.