Skip to main content

axilog (Python)

Python bindings (PyO3) for axilog's Rust GW2 arcdps WvW parsing core. Every export is a thin wrapper around the same decode → resolve → analyze → build_report pipeline the CLI (axilog-cli) and the Node SDK (crates/axilog-node) drive — see src/lib.rs's module doc for the exact FFI contract (no Rust panic ever crosses the boundary; every fallible step becomes a Python OSError/ValueError carrying the underlying Rust error text).

Build

cd crates/axilog-py
python3 -m venv .venv                 # gitignored; may live anywhere
.venv/bin/pip install maturin
.venv/bin/maturin develop --release   # builds the extension into .venv

maturin develop compiles this crate to a native extension module and installs it editable into whichever interpreter you point it at. Re-run it after changing src/lib.rs or axilog.pyi.

To build into a venv outside the crate — worth doing on a machine where the repo lives on a small or slow volume — set VIRTUAL_ENV so maturin targets it instead of guessing:

VIRTUAL_ENV=/path/to/venv /path/to/venv/bin/maturin develop --release

Usage

parse_file/parse_bytes return the native 1.0 container (schema: "1.0"), as a plain dict of dicts and lists. Its six top-level keys are always present:

Key What it is
axilog { schema, version, generated_from } — format contract version, the binary that produced the document, and the input log's file name
encounter One object: kind, map, duration_ms, teams[], markers[], objectives[], recorded_by, …
entities The single roster — every tracked agent, identity only, no statistics
catalogs skills/buffs/damage_mods/minions metadata, referenced by id from blocks
blocks Id-keyed statistics maps — damage, defenses, boons, support, …
coverage Per-block status: present, empty, not_computed or unsupported

A seventh key, warnings, appears only when non-empty.

There is no top-level players[] and no schema_version. The roster is entities[], and every per-entity statistic is a blocks.<name>.by_entity map keyed by entities[].id — as a string, since JSON object keys are strings while entities[].id is an int.

import axilog

report = axilog.parse_file("./fight.zevtc")

print(report["axilog"])
# {'generated_from': 'wvw-small.anon.zevtc', 'schema': '1.0', 'version': '0.3.2'}

print(report["encounter"]["map"], report["encounter"]["duration_ms"])
# Green Alpine Borderlands 49285

# The roster is filtered by `role`, not by a separate list. WvW logs carry
# four: "squad", "friendly_player", "enemy_player" and "npc".
squad = [e for e in report["entities"] if e["role"] == "squad"]
print(len(squad), "squad of", len(report["entities"]), "entities")
# 38 squad of 122 entities

damage = report["blocks"]["damage"]
print(damage["squad"]["total"])
# 2138414

top = max(squad, key=lambda e: damage["by_entity"][str(e["id"])]["total"])
row = damage["by_entity"][str(top["id"])]
print(top["account"], top["profession"], row["total"], round(row["dps"], 1))
# :Anon104.4848 Engineer 205612 4171.9

# Buffs are id-keyed too; names live once in the catalog, never repeated
# per entity.
boons = report["blocks"]["boons"]["by_entity"][str(top["id"])]
print(report["catalogs"]["buffs"]["1187"]["name"], round(boons["1187"]["uptime_pct"], 1))
# Quickness 6.0

# Same pipeline, from an already-read buffer.
with open("./fight.zevtc", "rb") as f:
    report_from_bytes = axilog.parse_bytes(f.read())

Check coverage before reading a block

coverage is how a consumer tells "the flag was off" apart from "the log had nothing to say", which is otherwise indistinguishable — both look like a missing block.

report = axilog.parse_file("./fight.zevtc")
print(report["coverage"]["rotation"], report["coverage"]["damage_mods"])
# empty not_computed
Value Meaning What to do
present Computed, has rows Read it
empty Computed, genuinely nothing to report Treat as zero rows, not an error. The block is still carried in blocks
not_computed The gate for it was off Re-parse with the gate on. Do not report this as "the log had none"
unsupported This log cannot produce it — its era, encounter kind, or recorder Do not retry with a gate; see docs/EI-PARITY.md

Opt-in gates

Seven keyword arguments, all False by default:

Keyword Adds
skill_damage=True blocks.damage.by_entity[].by_skill / .by_skill_taken — per-skill outgoing and incoming splits
timeseries=True blocks.series per-entity channels, the buff stack timelines in blocks.boons/blocks.conditions, and all of blocks.self_effects — squad-side condition/Stun/Daze uptime and stack timelines, which is gated on this flag in its entirety
rotation=True blocks.rotation.by_entity[].{casts, aftercast}
replay=True blocks.replay.tracks — position samples. The down/dead intervals under blocks.replay.by_entity are computed on every parse; only the positions are gated
missiles=True blocks.missiles — projectile fired/hit/denied counts
modifiers=True blocks.damage_mods and catalogs.damage_mods
everything=True Every analysis pass this version knows about
report = axilog.parse_file("./fight.zevtc", skill_damage=True, rotation=True)

row = report["blocks"]["damage"]["by_entity"]["1"]
print(sorted(row.keys()))
# ['breakbar_damage_dealt', 'by_skill', 'by_skill_taken', 'downs_dealt',
#  'dps', 'kills_dealt', 'per_target', 'taken', 'total']

Prefer everything=True over enumerating gates if you want complete documents: it is defined as "everything that exists in this version", so a pass added by a later release is included automatically. The first axibridge cutover audit found 30 blank fields caused by exactly the opposite — a consumer's option list drifting from the parser's. It is a union with the individual gates, never an override.

Gates are not free, and they are not uniformly the same kind of cost. skill_damage, timeseries and rotation only control whether an already-computed result is serialized; replay and modifiers gate the computation itself. Measured on the committed fixture (fixtures/wvw-small.anon.zevtc — 38 squad entities, 49.3 s — release build, compact JSON, 461,086-byte baseline at 0.07 s):

Gate Bytes Wall
(none) 461,086 0.07 s
missiles 466,565 0.07 s
rotation 708,367 0.07 s
modifiers 616,591 0.08 s
replay 1,679,284 0.12 s
skill_damage 3,338,819 0.08 s
timeseries 3,563,403 0.09 s
everything 8,067,599 0.16 s

That fixture is a 49-second skirmish. The per-skill and per-second blocks are combinatorial — entity × target × skill and entity × target × second — so on a real multi-minute zerg log they grow far faster than the table above suggests. See docs/BENCHMARKS.md for real-log numbers.

The other two functions

# Elite Insights-compatibility JSON (axilog_ei::to_ei_json) — the shape
# axibridge-style consumers read (players[].account, dpsAll[0].damage,
# support[0].condiCleanse, buffUptimes[], targets[].enemyPlayer,
# wvWMapData.{red,blue,green}TeamID). Returned as `Dict[str, Any]`; unlike
# the native container this one does still have a flat `players[]`, because
# EI's shape does. Gates are keyword-only and mirror `parse_file`'s, except
# `missiles`, which is accepted for signature parity and has no effect (EI's
# shape has no comparable field).
ei = axilog.parse_file_ei("./fight.zevtc")

# Rewrite every player's character/account name in a .zevtc to a
# deterministic Anon<N> placeholder (does not mutate metrics — safe for
# producing PII-safe fixtures). Returns the number of player agents
# rewritten.
rewritten = axilog.anonymize_file("./fight.zevtc", "./fight.anon.zevtc")

All four functions raise a real Python exception (never a raw Rust panic) on failure: OSError for a file that can't be read/written, ValueError for bytes that don't decode/parse as an arcdps log.

Further reference

docs/NATIVE-FORMAT.md in the repo root is the authoritative field-level reference for the 1.0 container — the entities[].role rules, the catalog join semantics, the series RLE envelope, the two replay halves, and the 1.x compatibility rules a consumer can rely on. This README is the SDK surface; that document is the format.

Types

This crate has no python-source tree — the compiled extension module is the package (see src/lib.rs's #[pymodule] fn axilog). maturin (>=1.5) auto-detects a <module_name>.pyi stub and a py.typed marker sitting next to Cargo.toml/pyproject.toml at the crate root and bundles both into the wheel as axilog/__init__.pyi and axilog/py.typed, alongside the compiled axilog/axilog.abi3.so and the auto-generated axilog/__init__.py — no [tool.maturin] include/ package-data configuration needed (verified directly against this crate: maturin build logs Found type stub file at axilog.pyi, and the built wheel contains axilog/__init__.pyi + axilog/py.typed).

axilog.pyi hand-transcribes the serialized shape into TypedDicts, with Optional/omitted-key semantics matching each field's serde Option/skip_serializing_if attributes exactly (see the top of axilog.pyi for the precise rule). The 1.0 container's types live under the # native format 1.0 heading — ReportV1, AxilogMeta, EncounterOutV1, EntityOut, Catalogs, Coverage, SeriesOut and friends, transcribed from crates/axilog-schema/src/v1/. It mirrors crates/axilog-node/types.d.ts's equivalent transcription for the Node SDK; keep the two in step.

parse_file/parse_bytes are typed to return ReportV1. parse_file_ei's materially different, larger EI-JSON shape is intentionally left Dict[str, Any] — typing it faithfully is out of scope, mirroring types.d.ts's same call for parseFileEi.

Tests

tests/test_sdk.py (stdlib unittest only, no pytest/other dependencies) covers, against the committed PII-safe fixture fixtures/wvw-small.anon.zevtc (repo-root relative, resolved from the test file's own location so it runs correctly from any cwd):

  • parse_file: the six-key container shape, player count, squad damage total, and the four support-stat squad sums — all pinned to this fixture's exact calibrated values (see crates/axilog-core/tests/golden.rs/support_golden.rs for how those numbers were derived against a real dps.report EI export). One boon uptime value is cross-checked live against fixtures/wvw-small.ei.json's players[].boons["1187"].uptime, rather than only pinned to a hardcoded literal.
  • parse_bytes equals parse_file.
  • replay, skill_damage, timeseries, missiles and modifiers: absent by default, present and correctly shaped when requested, and absent again when passed explicitly False. replay's test additionally pins the split halves — intervals always on, tracks gated — and asserts every track id joins to an entities[] row. rotation has no such test — in either SDK. Its shape and size are guarded schema-side (crates/axilog-schema/tests/v1_shape.rs's keyset golden and v1_size.rs, both of which drive every gate), but there is no absent-by-default/present-when-requested assertion for it at the SDK boundary. Known gap.
  • everything=True: every gate computes, leaving nothing not_computed in coverage.
  • parse_file_ei: the specific keys axibridge-style consumers read (players[].account, dpsAll[0].damage, support[0].condiCleanse, non-empty buffUptimes, targets[].enemyPlayer booleans, wvWMapData's three team ids).
  • anonymize_file round-trip: writes to a tempfile directory, re-parses, checks entity count/metrics are unchanged (anonymization only rewrites names).
  • Error paths: a missing file raises OSError; corrupt bytes raise ValueError — both with a non-empty message.
  • CLI parity: shells out to the already-built CLI (cargo build -p axilog-cli; run that first if target/debug/axilog is missing) and asserts axilog parse <fixture> --format json, json.loaded, exactly equals parse_file's return value — with a small first-N-differing-paths diff helper so a future divergence prints something readable instead of two giant dicts.

Canonical invocation, using the interpreter the module was built into:

.venv/bin/python -m unittest discover -s tests

Equivalently from the repo root, crates/axilog-py/.venv/bin/python -m unittest discover -s crates/axilog-py/tests. Substitute your own venv path if you built outside the crate.

Metadata

Release files for axilog 1.8.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for axilog 1.8.3
File Size Uploaded
axilog-1.8.3.tar.gz 1.5 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for axilog 1.8.3
File
axilog-1.8.3-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
axilog-1.8.3-cp39-abi3-manylinux_2_34_x86_64.whl CPython 3.9 abi3 Linux glibc 2.34+ x86-64 Details
axilog-1.8.3-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
axilog-1.8.3-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 8.5 MB

Release files / axilog-1.8.3.tar.gz

Download URL axilog-1.8.3.tar.gz
Size 1.5 MB
Tags Source
SHA-256 checksum
How to use checksums
b5cc71ae8efd6540a357327e0041c71cd3ad9fe81458d1d64d219e30d6e99fd8
BLAKE2b-256 checksum
How to use checksums
8aa2f00b6945966f2b78be8f42a6021a5c92cb12985067ec1242f1d119128557
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / axilog-1.8.3-cp39-abi3-win_amd64.whl

Download URL axilog-1.8.3-cp39-abi3-win_amd64.whl
Size 1.6 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
feac78e9dbe5ea80f3a8eff37c4f50400f1e61aab9e64ce57ca4915fb10f31da
BLAKE2b-256 checksum
How to use checksums
b9939bbc801a62d5f760bdb2dfe1cb587a80346d322c094857d91722583c9ffc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / axilog-1.8.3-cp39-abi3-manylinux_2_34_x86_64.whl

Download URL axilog-1.8.3-cp39-abi3-manylinux_2_34_x86_64.whl
Size 1.9 MB
Tags CPython 3.9 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
a9e5f5a099a6bca2868608143aaf4d0a936e709e7fad7cb94bce5bab9dccc230
BLAKE2b-256 checksum
How to use checksums
88b9137c170078bf1ecb5716932978e78990e3189db2c640a4f26a3831669f0f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / axilog-1.8.3-cp39-abi3-macosx_11_0_arm64.whl

Download URL axilog-1.8.3-cp39-abi3-macosx_11_0_arm64.whl
Size 1.7 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
9547d983d02de27c2850359a67946aedbb2ec28157aa429e1baa87f482e445b8
BLAKE2b-256 checksum
How to use checksums
0fae950f52d1cc8d137539029b43ca57e20e8ebd8d4309dd0cfe3c6afe43e884
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release files / axilog-1.8.3-cp39-abi3-macosx_10_12_x86_64.whl

Download URL axilog-1.8.3-cp39-abi3-macosx_10_12_x86_64.whl
Size 1.8 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
0cc3c96f63e12779d9965009781cc468aef0b17c8936a1a86489b081ac5d171f
BLAKE2b-256 checksum
How to use checksums
c35345ab1f0f884e61aa7c8472ca55448c90bcd83be6e1cb5031eac48f2e87cf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 29, 2026.

Transparency log

Release history Release notifications | RSS feed

1.14.0

5 release files

1.10.2

5 release files

1.10.1

5 release files

1.10.0

5 release files

1.9.0

5 release files

This release

1.8.3 This release

5 release files

1.8.2

5 release files

1.8.1

5 release files

1.8.0

5 release files

1.7.2

5 release files

1.7.1

5 release files

1.7.0

5 release files

1.6.2

5 release files

1.6.1

5 release files

1.6.0

5 release files

1.5.1

5 release files

1.5.0

5 release files

1.4.1

5 release files

1.4.0

5 release files

1.3.0

5 release files

1.2.0

5 release files

1.1.0

5 release files

1.0.0

5 release files

0.3.12

5 release files

0.3.11

5 release files

0.3.10

5 release files

0.3.9

5 release files

0.3.8

5 release files

0.3.7

5 release files

0.3.6

5 release files

0.3.5

5 release files

0.3.4

5 release files

0.3.3

5 release files

0.3.2

5 release files

0.3.1

5 release files

0.3.0

5 release files

0.2.0

5 release files

0.1.1

5 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page