A small Python CLI for listing, downloading, and comparing explicitly selected CNMV annual filings. It reads the official CNMV website directly.
Python 3.11 or newer and uv are required.
uv sync
uv run cnmv --helpuv run cnmv filing list --nif A08001851The default and only output format is JSON Lines: one filing object per line.
Each object includes its registration number, period end, publication date,
auditor, available audit details, and available source document URLs classified
as individual_xhtml, consolidated_xhtml, or consolidated_zip.
Pass an explicit HTTPS URL found in the list output:
uv run cnmv filing download \
--url 'https://www.cnmv.es/webservices/verdocumento/ver?e=…' \
--output downloads/filing.xhtmlThe command creates missing parent directories, streams up to 256 MiB into a
temporary file, and atomically replaces the output after a successful download.
It prints one JSON provenance object containing the final URL, SHA-256 digest,
byte count, content type, and output path. Only HTTPS URLs on cnmv.es or its
subdomains are accepted, including at every redirect.
Pass two explicit CNMV URLs and, optionally, a local database directory:
uv run cnmv filing compare \
--older-url 'https://www.cnmv.es/path/older.xhtml' \
--newer-url 'https://www.cnmv.es/path/newer.xhtml' \
--database .cnmv-filing-deltaThe database defaults to .cnmv-filing-delta. Both documents are downloaded
with the same HTTPS-origin, redirect, and size checks as filing download.
Only HTML/XHTML responses are accepted. Visible block text is stored in
persistent Chroma collections identified by each document's SHA-256 hash, so a
collection from another document cannot be silently reused.
The command prints one compact JSON object with the final URL, SHA-256 hash,
and byte count for both documents. Its changes list contains newer chunks that
are not present verbatim in the older filing; each entry has new_text,
closest_old_text, and distance. Embeddings are generated by a small
deterministic token-hash function and require no API key or model download.
uv sync
uv run pytest
uv run python -m compileall -q src testsThe default test suite uses local fixtures and mocked HTTP responses; it does not access the network.
The CLI checks workflow runs the
regression suite, lint, compilation, and installed-command help checks on Python
3.11 and 3.14 for every pull request, push to main, and nightly at 21:00 Madrid
time (Europe/Madrid, automatically adjusting for daylight saving time). It
also supports Run workflow in the repository's Actions tab.
Nightly and manual runs include a separate Live CNMV job. It lists filings
for A08001851, selects the latest two distinct periods with consolidated XHTML
documents, downloads one and verifies its hash and size, then compares the pair
using a temporary Chroma database. The job validates JSON output and provenance
and logs the selected periods, registration numbers, URLs, hashes, and change
count. It retries a reported upstream request failure once; persistent failures
fail the job. A live failure can also indicate a CNMV outage or page change.
To run the same live check locally:
CNMV_LIVE_TESTS=1 uv run pytest -v -s tests/test_live.pyNo API keys or repository secrets are required. Results and failing commands
appear in Actions; enable GitHub Actions notifications in your GitHub account
if you want email alerts. Scheduled runs begin once the workflow is on main;
GitHub may delay them and disables schedules in public repositories after 60
days without repository activity.
This MVP intentionally does not implement XBRL extraction, financial metrics, LLM-generated narrative, or external services.