pyxaf 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyxaf-0.1.0/CHANGELOG.md +65 -0
- pyxaf-0.1.0/LICENSE +21 -0
- pyxaf-0.1.0/PKG-INFO +366 -0
- pyxaf-0.1.0/README.md +314 -0
- pyxaf-0.1.0/pyproject.toml +287 -0
- pyxaf-0.1.0/pyproject.toml.orig +184 -0
- pyxaf-0.1.0/src/pyxaf/__init__.py +108 -0
- pyxaf-0.1.0/src/pyxaf/__main__.py +34 -0
- pyxaf-0.1.0/src/pyxaf/_adf.py +414 -0
- pyxaf-0.1.0/src/pyxaf/_arrow.py +239 -0
- pyxaf-0.1.0/src/pyxaf/_encoding.py +216 -0
- pyxaf-0.1.0/src/pyxaf/_normalize.py +676 -0
- pyxaf-0.1.0/src/pyxaf/_optional.py +20 -0
- pyxaf-0.1.0/src/pyxaf/_source.py +296 -0
- pyxaf-0.1.0/src/pyxaf/_xml.py +337 -0
- pyxaf-0.1.0/src/pyxaf/_xsd.py +147 -0
- pyxaf-0.1.0/src/pyxaf/catalogue/__init__.py +140 -0
- pyxaf-0.1.0/src/pyxaf/catalogue/_generated_clair2.py +98 -0
- pyxaf-0.1.0/src/pyxaf/catalogue/_generated_xaf30.py +228 -0
- pyxaf-0.1.0/src/pyxaf/catalogue/_generated_xaf31.py +229 -0
- pyxaf-0.1.0/src/pyxaf/catalogue/_generated_xaf32.py +308 -0
- pyxaf-0.1.0/src/pyxaf/catalogue/_generated_xaf321.py +308 -0
- pyxaf-0.1.0/src/pyxaf/catalogue/_generated_xaf40.py +121 -0
- pyxaf-0.1.0/src/pyxaf/cli.py +293 -0
- pyxaf-0.1.0/src/pyxaf/detect.py +314 -0
- pyxaf-0.1.0/src/pyxaf/errors.py +72 -0
- pyxaf-0.1.0/src/pyxaf/findings.py +326 -0
- pyxaf-0.1.0/src/pyxaf/formats.py +132 -0
- pyxaf-0.1.0/src/pyxaf/models.py +622 -0
- pyxaf-0.1.0/src/pyxaf/py.typed +0 -0
- pyxaf-0.1.0/src/pyxaf/raw.py +88 -0
- pyxaf-0.1.0/src/pyxaf/reader.py +842 -0
- pyxaf-0.1.0/src/pyxaf/rgs/__init__.py +571 -0
- pyxaf-0.1.0/src/pyxaf/rgs/_xlsx.py +483 -0
- pyxaf-0.1.0/src/pyxaf/schemas/NOTICE.md +13 -0
- pyxaf-0.1.0/src/pyxaf/schemas/XmlAuditfileFinancieel3.2.1.xsd +1144 -0
- pyxaf-0.1.0/src/pyxaf/schemas/XmlAuditfileFinancieel3.2.xsd +1183 -0
- pyxaf-0.1.0/src/pyxaf/schemas/XmlAuditfileFinancieel4.0.xsd +349 -0
- pyxaf-0.1.0/src/pyxaf/schemas/clair2-auditfile.xsd +547 -0
- pyxaf-0.1.0/src/pyxaf/tables.py +482 -0
- pyxaf-0.1.0/src/pyxaf/validate.py +1079 -0
- pyxaf-0.1.0/src/pyxaf/values.py +112 -0
- pyxaf-0.1.0/tests/conftest.py +18 -0
- pyxaf-0.1.0/tests/test_cli.py +91 -0
- pyxaf-0.1.0/tests/test_detect.py +131 -0
- pyxaf-0.1.0/tests/test_properties.py +52 -0
- pyxaf-0.1.0/tests/test_reader.py +358 -0
- pyxaf-0.1.0/tests/test_readme.py +65 -0
- pyxaf-0.1.0/tests/test_regressions.py +123 -0
- pyxaf-0.1.0/tests/test_rgs.py +553 -0
- pyxaf-0.1.0/tests/test_security.py +85 -0
- pyxaf-0.1.0/tests/test_tables.py +154 -0
- pyxaf-0.1.0/tests/test_validate.py +332 -0
- pyxaf-0.1.0/tests/test_values.py +69 -0
- pyxaf-0.1.0/tests/test_xsd_and_catalogue.py +69 -0
- pyxaf-0.1.0/tests/xafgen.py +647 -0
pyxaf-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
6
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Until 1.0 the public API may
|
|
7
|
+
change in minor releases. Finding codes are stable: a code is never renumbered or reused.
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
## [0.1.0] - 2026-10-01
|
|
12
|
+
|
|
13
|
+
Initial release.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Reading every iteration** of the Dutch Auditfile Financieel: XML Auditfile Financieel 4.0,
|
|
18
|
+
3.2.1, 3.2, 3.1 and 3.0, CLAIR2 and the fixed-width ADF (CLAIR1) format, through one
|
|
19
|
+
`pyxaf.open()` API with a normalized, typed data model (company, ledger accounts with RGS
|
|
20
|
+
references, customers/suppliers, VAT codes, periods, journals, transactions, lines, opening
|
|
21
|
+
balance). The original raw records stay available next to the parsed values.
|
|
22
|
+
- **Streaming**: transactions and lines are streamed, so memory does not grow with file size.
|
|
23
|
+
Multi-file sets are supported: continuation files ("Vervolgbestand x van y") are read as one
|
|
24
|
+
document, per-period files are merged (master data deduplicated, conflicts reported).
|
|
25
|
+
- **Robust input**: corrupt archives raise `CorruptArchiveError`; encodings Expat lacks
|
|
26
|
+
(windows-125x, UTF-32, …) are transcoded; Arrow-based exports take `on_inexact=`.
|
|
27
|
+
- **Raw access**: `af.raw.header`, `af.raw.company` and `af.raw.transactions()` stream the
|
|
28
|
+
lossless raw records without normalization (about twice as fast).
|
|
29
|
+
- **Exact values**: amounts are `decimal.Decimal` with the raw text kept; amounts with 0–2
|
|
30
|
+
decimals, negative amounts and opaque period numbers are handled. The opening balance is unified
|
|
31
|
+
from the `openingBalance` element or period-0/opening-journal transactions.
|
|
32
|
+
- **Input handling**: paths, bytes and binary streams; transparent gzip and single-member zip;
|
|
33
|
+
UTF-8 (with or without BOM), ISO-8859-1 and windows-1252, `encoding=` override and opt-in,
|
|
34
|
+
reported repairs (`control-chars`, `latin1-as-cp1252`, `bare-ampersand`). Encrypted
|
|
35
|
+
tax-authority containers are recognised and rejected with an explanatory error.
|
|
36
|
+
- **Version detection** (`pyxaf.detect()`) by scoring signals (namespace, vocabulary, ADF
|
|
37
|
+
signature, continuation comment) rather than namespace alone, with confidence, reasons and the
|
|
38
|
+
namespace status (official, documented variant, known bogus, none).
|
|
39
|
+
- **Validation** (`pyxaf.validate()`) with graded, coded findings (`XAF<nnnn>`, severities
|
|
40
|
+
ERROR/WARNING/INFO, documented in `pyxaf.CODES`): encoding, XML well-formedness, structure per
|
|
41
|
+
version (required elements, cardinality, lengths, code lists, patterns), references, control
|
|
42
|
+
totals and balance, uniqueness and data quality. The official XAF 4.0 consistency rules
|
|
43
|
+
[0001]–[0010] map to codes; rule sets `spec` and `vts`; per-code and overall finding limits.
|
|
44
|
+
Data problems never stop a file from loading.
|
|
45
|
+
- **Field catalogues** for every XML iteration, generated from the official XSDs
|
|
46
|
+
(`scripts/gen_catalogues.py`).
|
|
47
|
+
- **XSD validation** against the bundled official schemas (CLAIR2, 3.2, 3.2.1, 4.0) with the
|
|
48
|
+
`xsd` extra (lxml >= 6.1.3, hardened parser options).
|
|
49
|
+
- **Normalized tables and exports**: fixed-schema tables (`header`, `company`, `addresses`,
|
|
50
|
+
`accounts`, `relations`, `vat_codes`, `periods`, `journals`, `transactions`, `lines`,
|
|
51
|
+
`line_vat`, `opening_balance`); CSV and JSON Lines with the standard library; Arrow streams
|
|
52
|
+
with exact `decimal128` columns (`arrow` extra, nanoarrow); `to_polars()` (`polars` extra),
|
|
53
|
+
`to_pandas()` (`pandas` extra) and Parquet (`parquet` extra).
|
|
54
|
+
- **RGS** (`pyxaf.rgs`): load the official RGS Excel release with a small standard-library
|
|
55
|
+
`.xlsx` reader, resolve codes and their hierarchy, and check the RGS references of an auditfile.
|
|
56
|
+
No RGS data is bundled.
|
|
57
|
+
- **Command line** (`cli` extra): `pyxaf detect`, `info`, `validate` (text or JSON output,
|
|
58
|
+
`--strict`), `export` and `codes`, with documented exit codes. Without the extra, `pyxaf` prints
|
|
59
|
+
an install hint.
|
|
60
|
+
- **Security hardening** for untrusted input: DOCTYPE/ENTITY declarations are refused, no
|
|
61
|
+
network or entity resolution, limits on nesting depth, text-node size and decompressed size.
|
|
62
|
+
- Zero runtime dependencies in the core; fully typed (`py.typed`); Python 3.11–3.14.
|
|
63
|
+
|
|
64
|
+
[Unreleased]: https://github.com/SpireflyHQ/pyxaf/compare/v0.1.0...HEAD
|
|
65
|
+
[0.1.0]: https://github.com/SpireflyHQ/pyxaf/releases/tag/v0.1.0
|
pyxaf-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ben van der Burgh and the pyxaf contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pyxaf-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyxaf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Read and validate every iteration of the Dutch XML Auditfile Financieel (XAF 4.0, 3.2.1, 3.2, 3.1, 3.0, CLAIR2 and ADF).
|
|
5
|
+
Keywords: xaf,auditfile,auditfile financieel,accounting,audit,general ledger,rgs,belastingdienst,saf-t,xml
|
|
6
|
+
Author: Ben van der Burgh
|
|
7
|
+
Author-email: Ben van der Burgh <ben@spirefly.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: Natural Language :: English
|
|
14
|
+
Classifier: Natural Language :: Dutch
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Office/Business :: Financial :: Accounting
|
|
23
|
+
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
24
|
+
Classifier: Typing :: Typed
|
|
25
|
+
Requires-Dist: pyxaf[xsd,arrow,polars,pandas,parquet,cli] ; extra == 'all'
|
|
26
|
+
Requires-Dist: nanoarrow>=0.7 ; extra == 'arrow'
|
|
27
|
+
Requires-Dist: typer>=0.16 ; extra == 'cli'
|
|
28
|
+
Requires-Dist: pandas>=2.2 ; extra == 'pandas'
|
|
29
|
+
Requires-Dist: pyarrow>=17 ; extra == 'pandas'
|
|
30
|
+
Requires-Dist: nanoarrow>=0.7 ; extra == 'pandas'
|
|
31
|
+
Requires-Dist: pyarrow>=17 ; extra == 'parquet'
|
|
32
|
+
Requires-Dist: nanoarrow>=0.7 ; extra == 'parquet'
|
|
33
|
+
Requires-Dist: polars>=1.44 ; extra == 'polars'
|
|
34
|
+
Requires-Dist: nanoarrow>=0.7 ; extra == 'polars'
|
|
35
|
+
Requires-Dist: lxml>=6.1.3 ; extra == 'xsd'
|
|
36
|
+
Maintainer: Ben van der Burgh
|
|
37
|
+
Maintainer-email: Ben van der Burgh <ben@spirefly.com>
|
|
38
|
+
Requires-Python: >=3.11
|
|
39
|
+
Project-URL: Homepage, https://github.com/SpireflyHQ/pyxaf
|
|
40
|
+
Project-URL: Documentation, https://spireflyhq.github.io/pyxaf/
|
|
41
|
+
Project-URL: Repository, https://github.com/SpireflyHQ/pyxaf
|
|
42
|
+
Project-URL: Issues, https://github.com/SpireflyHQ/pyxaf/issues
|
|
43
|
+
Project-URL: Changelog, https://github.com/SpireflyHQ/pyxaf/blob/main/CHANGELOG.md
|
|
44
|
+
Provides-Extra: all
|
|
45
|
+
Provides-Extra: arrow
|
|
46
|
+
Provides-Extra: cli
|
|
47
|
+
Provides-Extra: pandas
|
|
48
|
+
Provides-Extra: parquet
|
|
49
|
+
Provides-Extra: polars
|
|
50
|
+
Provides-Extra: xsd
|
|
51
|
+
Description-Content-Type: text/markdown
|
|
52
|
+
|
|
53
|
+
# 📒 pyxaf
|
|
54
|
+
|
|
55
|
+
[](https://github.com/SpireflyHQ/pyxaf/actions/workflows/ci.yml)
|
|
56
|
+
[](https://pypi.org/project/pyxaf/)
|
|
57
|
+
[](https://pypi.org/project/pyxaf/)
|
|
58
|
+
[](https://github.com/SpireflyHQ/pyxaf/blob/main/LICENSE)
|
|
59
|
+
|
|
60
|
+
**Read and validate every version of the Dutch Auditfile Financieel in plain Python.**
|
|
61
|
+
|
|
62
|
+
The *Auditfile Financieel* is the standard export of a general ledger that Dutch accounting
|
|
63
|
+
software produces for tax inspectors and auditors. pyxaf opens all seven versions of it, from the
|
|
64
|
+
fixed-width files of 1999 to XAF 4.0, gives you one clean, typed model to work with, and tells
|
|
65
|
+
you exactly what is wrong with a file instead of choking on it. No runtime dependencies, no
|
|
66
|
+
upload to anyone's server, no gigabytes of RAM.
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import pyxaf
|
|
70
|
+
|
|
71
|
+
with pyxaf.open("2024.xaf") as af:
|
|
72
|
+
print(af.version, af.company.name) # 4.0 Voorbeeld & Zonen B.V.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 🧭 Table of contents
|
|
76
|
+
|
|
77
|
+
- [Why pyxaf](#-why-pyxaf)
|
|
78
|
+
- [Installation](#-installation)
|
|
79
|
+
- [Quickstart](#-quickstart)
|
|
80
|
+
- [1. Open the file](#1-open-the-file)
|
|
81
|
+
- [2. Walk through the transactions](#2-walk-through-the-transactions)
|
|
82
|
+
- [3. Validate it](#3-validate-it)
|
|
83
|
+
- [4. Or use the command line](#4-or-use-the-command-line)
|
|
84
|
+
- [More examples](#-more-examples)
|
|
85
|
+
- [Export to tables](#export-to-tables)
|
|
86
|
+
- [Query with DuckDB or pyarrow](#query-with-duckdb-or-pyarrow)
|
|
87
|
+
- [Check RGS codes](#check-rgs-codes)
|
|
88
|
+
- [Split files and problem files](#split-files-and-problem-files)
|
|
89
|
+
- [Supported versions](#-supported-versions)
|
|
90
|
+
- [Documentation](#-documentation)
|
|
91
|
+
- [Contributing](#-contributing)
|
|
92
|
+
- [License and attribution](#-license-and-attribution)
|
|
93
|
+
|
|
94
|
+
## ✨ Why pyxaf
|
|
95
|
+
|
|
96
|
+
Real auditfiles are messy. Official test files break the official rules, vendors invent their own
|
|
97
|
+
namespaces, and an "ISO-8859-1" file turns out to be Windows-1252. pyxaf was built for those files.
|
|
98
|
+
|
|
99
|
+
- **All versions, one model.** XAF 4.0, 3.2.1, 3.2, 3.1, 3.0, CLAIR2 and the fixed-width ADF all
|
|
100
|
+
map onto the same classes: `Header`, `LedgerAccount`, `Transaction`, `Line` and friends. The
|
|
101
|
+
raw layer keeps every element exactly as written, vendor extensions included.
|
|
102
|
+
- **Lenient reading, honest reporting.** pyxaf never refuses a file because of bad data. Every
|
|
103
|
+
problem becomes a graded finding with a stable code, such as `XAF5010 ERROR`, so nothing is
|
|
104
|
+
silently guessed or dropped.
|
|
105
|
+
- **A validator on your own machine.** The official validation service is for subscribers and
|
|
106
|
+
stops at 5 MB. pyxaf checks files of any size: structure, references, control totals,
|
|
107
|
+
balance, uniqueness, data quality and RGS codes, including the official XAF 4.0 rules
|
|
108
|
+
[0001]–[0010].
|
|
109
|
+
- **Exact money.** Amounts are `decimal.Decimal`, never `float`, with the original text kept
|
|
110
|
+
next to every parsed value.
|
|
111
|
+
- **Streaming.** Master data is read when the file opens; transactions and lines are streamed,
|
|
112
|
+
so memory stays flat even for files of several gigabytes.
|
|
113
|
+
- **Lightweight.** The core uses only the standard library and is fully typed. pandas, polars,
|
|
114
|
+
Arrow, lxml and the command line are optional extras that are only imported when you use them.
|
|
115
|
+
- **Safe with untrusted files.** DOCTYPE and ENTITY declarations are refused (no "billion
|
|
116
|
+
laughs", no XXE), nesting, text and decompression sizes are capped, and there is no "recover"
|
|
117
|
+
mode that could quietly lose data.
|
|
118
|
+
|
|
119
|
+
## 📦 Installation
|
|
120
|
+
|
|
121
|
+
pyxaf needs Python 3.11 or newer.
|
|
122
|
+
|
|
123
|
+
```console
|
|
124
|
+
pip install pyxaf
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The core has no dependencies. Add an extra for each optional feature you need:
|
|
128
|
+
|
|
129
|
+
| Extra | Adds | Install |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| `cli` | the `pyxaf` command line | `pip install "pyxaf[cli]"` |
|
|
132
|
+
| `xsd` | validation against the official XSDs (lxml) | `pip install "pyxaf[xsd]"` |
|
|
133
|
+
| `polars` | `to_polars()`, without pyarrow | `pip install "pyxaf[polars]"` |
|
|
134
|
+
| `pandas` | `to_pandas()` with Arrow-backed types | `pip install "pyxaf[pandas]"` |
|
|
135
|
+
| `arrow` | Arrow streams for DuckDB, pyarrow and friends (nanoarrow) | `pip install "pyxaf[arrow]"` |
|
|
136
|
+
| `parquet` | Parquet export | `pip install "pyxaf[parquet]"` |
|
|
137
|
+
| `all` | everything above | `pip install "pyxaf[all]"` |
|
|
138
|
+
|
|
139
|
+
Using uv? `uv add pyxaf` works the same way, for example `uv add "pyxaf[cli,polars]"`.
|
|
140
|
+
|
|
141
|
+
## 🚀 Quickstart
|
|
142
|
+
|
|
143
|
+
Grab an auditfile exported from your accounting software. The examples use `2024.xaf`, but any
|
|
144
|
+
version works, and so do `.gz` and `.zip` files.
|
|
145
|
+
|
|
146
|
+
### 1. Open the file
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
import pyxaf
|
|
150
|
+
|
|
151
|
+
af = pyxaf.open("2024.xaf")
|
|
152
|
+
print(af.version, af.company.name, af.header.fiscal_year)
|
|
153
|
+
print(len(af.accounts), "ledger accounts")
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
4.0 Voorbeeld & Zonen B.V. 2024
|
|
158
|
+
11 ledger accounts
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
pyxaf detected the version and encoding, and read the master data: company, ledger accounts,
|
|
162
|
+
customers and suppliers, VAT codes and periods.
|
|
163
|
+
|
|
164
|
+
### 2. Walk through the transactions
|
|
165
|
+
|
|
166
|
+
Transactions and their lines are streamed straight from the file, one at a time:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
for tx in af.transactions():
|
|
170
|
+
print(tx.journal_id, tx.number, tx.date, tx.description, tx.balanced)
|
|
171
|
+
for line in tx.lines:
|
|
172
|
+
print(" ", line.account_id, line.side, line.amount)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
MEM 1 2024-01-05 Boeking 1 True
|
|
177
|
+
1300 D 3612.16
|
|
178
|
+
8000 C 2985.26
|
|
179
|
+
1800 C 626.90
|
|
180
|
+
...
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The opening balance gets the same treatment, whichever way the file stores it:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
print(af.opening_balance().by_account()) # signed: debit positive, credit negative
|
|
187
|
+
af.close()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```text
|
|
191
|
+
{'1100': Decimal('10000.00'), '0100': Decimal('2500.50'), '0500': Decimal('-12500.50')}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 3. Validate it
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
report = pyxaf.validate("2024.xaf")
|
|
198
|
+
print(report.ok)
|
|
199
|
+
for finding in report.errors:
|
|
200
|
+
print(finding.code, finding.line, finding.message)
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
A clean file prints `True`. A file in which someone typed `3621.16` instead of `3612.16` prints:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
False
|
|
207
|
+
XAF5007 None transactions totalDebit 38260.42 ≠ sum of debit lines 38269.42
|
|
208
|
+
XAF5010 223 transaction '1' in journal 'MEM' does not balance: debit 3621.16, credit 3612.16
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Every finding has a stable code, a severity (`ERROR`, `WARNING` or `INFO`) and, where possible,
|
|
212
|
+
a line number. The [finding-code reference](https://spireflyhq.github.io/pyxaf/reference/codes/)
|
|
213
|
+
explains each one.
|
|
214
|
+
|
|
215
|
+
### 4. Or use the command line
|
|
216
|
+
|
|
217
|
+
With `pyxaf[cli]` installed:
|
|
218
|
+
|
|
219
|
+
```console
|
|
220
|
+
$ pyxaf validate 2024.xaf
|
|
221
|
+
== 2024.xaf
|
|
222
|
+
4.0 — 0 error(s), 0 warning(s), 0 info
|
|
223
|
+
|
|
224
|
+
$ pyxaf info 2024.xaf
|
|
225
|
+
version 4.0
|
|
226
|
+
company Voorbeeld & Zonen B.V.
|
|
227
|
+
fiscal year 2024
|
|
228
|
+
transactions 12
|
|
229
|
+
lines 36
|
|
230
|
+
total debit 38260.42
|
|
231
|
+
total credit 38260.42
|
|
232
|
+
...
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`pyxaf validate` exits with 0 when the file is fine, 1 for warnings (with `--strict`), 2 for
|
|
236
|
+
errors and 3 when pyxaf itself could not do its job, so it slots straight into scripts and CI.
|
|
237
|
+
|
|
238
|
+
## 🧰 More examples
|
|
239
|
+
|
|
240
|
+
### Export to tables
|
|
241
|
+
|
|
242
|
+
pyxaf turns a file into twelve normalized tables, such as `accounts`, `transactions` and `lines`,
|
|
243
|
+
with the same columns for every version:
|
|
244
|
+
|
|
245
|
+
```python
|
|
246
|
+
with pyxaf.open("2024.xaf") as af:
|
|
247
|
+
af.export("out/", format="csv") # standard library only; also "jsonl"
|
|
248
|
+
af.export("out/", format="parquet") # pyxaf[parquet]
|
|
249
|
+
frames = af.to_polars() # pyxaf[polars]: a dict of DataFrames
|
|
250
|
+
frames["lines"] # amounts as Decimal(20, 2), not float
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Query with DuckDB or pyarrow
|
|
254
|
+
|
|
255
|
+
Tables speak the Arrow PyCapsule interface, so Arrow-aware tools read them directly
|
|
256
|
+
(needs `pyxaf[arrow]`):
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
import duckdb
|
|
260
|
+
|
|
261
|
+
with pyxaf.open("2024.xaf") as af:
|
|
262
|
+
lines = af.tables["lines"]
|
|
263
|
+
duckdb.sql("select account_id, sum(signed_amount) from lines group by account_id").show()
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Check RGS codes
|
|
267
|
+
|
|
268
|
+
pyxaf reads each account's RGS (Referentie Grootboekschema) code. Load the official RGS Excel
|
|
269
|
+
release you downloaded, and the validator checks every code against it:
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
import pyxaf.rgs
|
|
273
|
+
|
|
274
|
+
schema = pyxaf.rgs.load_excel("RGS 3.8-def.xlsx")
|
|
275
|
+
report = pyxaf.validate("2024.xaf", rgs=schema)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Split files and problem files
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
# a split auditfile ("Vervolgbestand 2 van 3") or one file per period, read as one
|
|
282
|
+
with pyxaf.open(["big.xaf", "big-2.xaf", "big-3.xaf"]) as af:
|
|
283
|
+
...
|
|
284
|
+
|
|
285
|
+
# a file that lies about its encoding, with stray control characters and bare "&"
|
|
286
|
+
af = pyxaf.open("old.xaf", encoding="cp1252", repair={"control-chars", "bare-ampersand"})
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Repairs are opt-in and every repair shows up as a finding, so you always know what was changed.
|
|
290
|
+
|
|
291
|
+
<details>
|
|
292
|
+
<summary><b>Go deeper: raw records, detection details and the official XSDs</b></summary>
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
with pyxaf.open("2024.xaf") as af:
|
|
296
|
+
af.format # FormatInfo: version, namespace status, encoding, reasons
|
|
297
|
+
af.accounts["1000"].rgs # RgsRef(code='BLimKas', source='RGScode', ...)
|
|
298
|
+
for journal_id, record in af.raw.transactions():
|
|
299
|
+
... # lossless raw records, about twice as fast
|
|
300
|
+
|
|
301
|
+
report = pyxaf.validate("2024.xaf", xsd=True) # also check the official XSD (pyxaf[xsd])
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
</details>
|
|
305
|
+
|
|
306
|
+
## 📜 Supported versions
|
|
307
|
+
|
|
308
|
+
| Version | Year | How pyxaf recognises it |
|
|
309
|
+
|---|---|---|
|
|
310
|
+
| XAF 4.0 (4.0.3) | 2025 | namespace (including known variants) and 4.0-only elements |
|
|
311
|
+
| XAF 3.2.1 | 2024 | its own ODB namespace |
|
|
312
|
+
| XAF 3.2 | 2014, 2017 | `http://www.auditfiles.nl/XAF/3.2` |
|
|
313
|
+
| XAF 3.1 and 3.0 | ~2010, ~2008 | namespace and vocabulary (no public XSD exists) |
|
|
314
|
+
| CLAIR2 | 2003 | `header/auditfileVersion` is `CLAIR2.00.00`, no namespace |
|
|
315
|
+
| ADF | 1999 | fixed-width ASCII starting with `CLAIR1.00.00` |
|
|
316
|
+
|
|
317
|
+
From 1 January 2027 the Belastingdienst only accepts XAF 4.0. Older files stay around for years
|
|
318
|
+
because of the seven-year retention period, which is why pyxaf reads them all.
|
|
319
|
+
|
|
320
|
+
## 📚 Documentation
|
|
321
|
+
|
|
322
|
+
The full documentation lives at **<https://spireflyhq.github.io/pyxaf/>**:
|
|
323
|
+
|
|
324
|
+
- [Reading auditfiles](https://spireflyhq.github.io/pyxaf/guide/reading/): the data model,
|
|
325
|
+
streaming, opening balances, encodings and repairs
|
|
326
|
+
- [Versions](https://spireflyhq.github.io/pyxaf/guide/versions/): how the seven versions differ
|
|
327
|
+
and the field mapping across all of them
|
|
328
|
+
- [Validation](https://spireflyhq.github.io/pyxaf/guide/validation/) and the
|
|
329
|
+
[finding codes](https://spireflyhq.github.io/pyxaf/reference/codes/)
|
|
330
|
+
- [Interoperability](https://spireflyhq.github.io/pyxaf/guide/interop/),
|
|
331
|
+
[RGS](https://spireflyhq.github.io/pyxaf/guide/rgs/) and the
|
|
332
|
+
[command line](https://spireflyhq.github.io/pyxaf/guide/cli/)
|
|
333
|
+
- [Security](https://spireflyhq.github.io/pyxaf/security/) and
|
|
334
|
+
[versioning](https://spireflyhq.github.io/pyxaf/versioning/)
|
|
335
|
+
|
|
336
|
+
Release notes are in the [changelog](https://github.com/SpireflyHQ/pyxaf/blob/main/CHANGELOG.md).
|
|
337
|
+
For questions, see [SUPPORT.md](https://github.com/SpireflyHQ/pyxaf/blob/main/SUPPORT.md).
|
|
338
|
+
|
|
339
|
+
## 🤝 Contributing
|
|
340
|
+
|
|
341
|
+
Contributions are very welcome, especially reports of files from software that pyxaf does not
|
|
342
|
+
handle well yet. Start with [CONTRIBUTING.md](https://github.com/SpireflyHQ/pyxaf/blob/main/CONTRIBUTING.md)
|
|
343
|
+
for the development setup, and [ARCHITECTURE.md](https://github.com/SpireflyHQ/pyxaf/blob/main/ARCHITECTURE.md)
|
|
344
|
+
for a map of the code. Issues labelled
|
|
345
|
+
[good first issue](https://github.com/SpireflyHQ/pyxaf/labels/good%20first%20issue) are a good
|
|
346
|
+
place to begin.
|
|
347
|
+
|
|
348
|
+
> **Never attach a real auditfile** to an issue or pull request. Auditfiles contain personal data
|
|
349
|
+
> and confidential financial records. The version, the exporting software, the finding codes and
|
|
350
|
+
> a small hand-made snippet are all we need.
|
|
351
|
+
|
|
352
|
+
Security problems are reported privately, as described in
|
|
353
|
+
[SECURITY.md](https://github.com/SpireflyHQ/pyxaf/blob/main/SECURITY.md).
|
|
354
|
+
|
|
355
|
+
## 📄 License and attribution
|
|
356
|
+
|
|
357
|
+
pyxaf is released under the [MIT license](https://github.com/SpireflyHQ/pyxaf/blob/main/LICENSE).
|
|
358
|
+
|
|
359
|
+
The bundled XML schemas are published by the Belastingdienst (XAF 3.2.1 and 4.0), the former
|
|
360
|
+
auditfiles.nl platform (XAF 3.2) and SRA (CLAIR2). The XAF 3.0 and 3.1 element lists are derived
|
|
361
|
+
from the AnalyticsLibrary "XAF Mapping en Namen" table (Apache-2.0). RGS data is not bundled;
|
|
362
|
+
load the official Excel release yourself with `pyxaf.rgs.load_excel`.
|
|
363
|
+
|
|
364
|
+
pyxaf is an independent open-source project. It is not affiliated with or endorsed by the
|
|
365
|
+
Belastingdienst, the Taakgroep RGS or any software vendor, and a clean pyxaf report does not
|
|
366
|
+
guarantee that the Belastingdienst will accept a file.
|