gaeb 0.5.2__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.
gaeb-0.5.2/PKG-INFO ADDED
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.3
2
+ Name: gaeb
3
+ Version: 0.5.2
4
+ Summary: Python library for reading, writing, converting and diffing GAEB files (AVA data exchange format, DA XML 2.0–3.3, GAEB 90, GAEB 2000)
5
+ Keywords: gaeb,ava,construction,leistungsverzeichnis,bau,gaeb90,gaeb2000,xml,excel,diff
6
+ Author: Attackwave
7
+ Author-email: Attackwave <attackwave@gmail.com>
8
+ License: MIT
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Office/Business
18
+ Requires-Dist: pydantic>=2.0
19
+ Requires-Dist: lxml>=4.9.4
20
+ Requires-Dist: pytest>=7.0 ; extra == 'dev'
21
+ Requires-Dist: pytest-cov>=4.0 ; extra == 'dev'
22
+ Requires-Dist: openpyxl>=3.1 ; extra == 'excel'
23
+ Requires-Python: >=3.10
24
+ Project-URL: Homepage, https://github.com/Attackwave/gaeb-python
25
+ Project-URL: Repository, https://github.com/Attackwave/gaeb-python
26
+ Project-URL: Issues, https://github.com/Attackwave/gaeb-python/issues
27
+ Project-URL: Changelog, https://github.com/Attackwave/gaeb-python/blob/main/CHANGELOG.md
28
+ Provides-Extra: dev
29
+ Provides-Extra: excel
30
+ Description-Content-Type: text/markdown
31
+
32
+ # gaeb
33
+
34
+ Python-Bibliothek zum Lesen, Schreiben, Konvertieren und Vergleichen von **GAEB-Dateien** (AVA – Ausschreibung, Vergabe, Abrechnung im deutschen Bauwesen).
35
+
36
+ ## Features
37
+
38
+ - **GAEB DA XML 2.0–3.3** lesen und schreiben (automatische Versionserkennung, Multi-Version Writer)
39
+ - **GAEB 90** lesen und schreiben (`.d80`–`.d89`; Encoding-Autoerkennung)
40
+ - **GAEB 2000** lesen und schreiben (`.p80`–`.p89`)
41
+ - **Alle Austauschphasen**: Mengenermittlung (31), Kostenermittlung (50–52), Vergabe (80–89, 83Z, 84Z, 86ZR, 86ZE), Handel/Handwerk (93–97)
42
+ - **BoQ Builder**: programmatischer LV-Aufbau mit Auto-OZ-Generierung und Fluent API
43
+ - **Excel-Export** (.xlsx) mit Hierarchie-Layout — optional via `pip install gaeb[excel]`
44
+ - **Document Diff**: zwei LVs vergleichen, alle Felder prüfen, finanzielle Auswirkungen berechnen
45
+ - **XSD-Validierung** gegen offizielle GAEB-Schemas (Phasen 80–87)
46
+ - **Preisspiegel- & Raumbuch-Modell** für Angebotsvergleiche und räumliche Zuordnung
47
+ - **Security-Hardened**: XXE-Prevention, Billion-Laughs-Schutz, Dateigrössen-Limit, Rekursionstiefenbegrenzung
48
+ - Einheitliches **Pydantic v2** Datenmodell für alle Formate
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install gaeb
54
+
55
+ # Mit Excel-Export
56
+ pip install gaeb[excel]
57
+ ```
58
+
59
+ ## Schnellstart
60
+
61
+ ```python
62
+ import gaeb
63
+
64
+ # Lesen
65
+ lv = gaeb.read_xml("ausschreibung.x83")
66
+ lv = gaeb.read_gaeb90("ausschreibung.d83")
67
+ lv = gaeb.read_gaeb2000("ausschreibung.p83")
68
+
69
+ # Metadaten
70
+ print(lv.titel_lv) # LV-Titel
71
+ print(lv.phase) # Phase.ANGEBOTSAUFFORDERUNG
72
+ print(lv.xml_version) # "3.3" (nur bei DA XML)
73
+ print(lv.encoding) # "cp850" (nur bei GAEB 90 / 2000)
74
+ print(lv.gesamtsumme) # Decimal oder None
75
+
76
+ # Positionen
77
+ for pos in lv.alle_positionen:
78
+ print(pos.oz, pos.kurztext, pos.menge, pos.einheit)
79
+
80
+ # Schreiben / Konvertieren
81
+ gaeb.write_xml(lv, "ausgabe.x83")
82
+ gaeb.write_xml(lv, "ausgabe_v32.x83", version="3.2") # explizite Version
83
+ gaeb.write_gaeb90(lv, "ausgabe.d83")
84
+ gaeb.write_gaeb2000(lv, "ausgabe.p83")
85
+
86
+ # Excel-Export
87
+ gaeb.write_excel(lv, "ausgabe.xlsx")
88
+ gaeb.write_excel(lv, "ausgabe.xlsx", langtext=True)
89
+
90
+ # Zwei LVs vergleichen
91
+ lv_neu = gaeb.read_xml("angebot.x84")
92
+ result = gaeb.vergleiche(lv, lv_neu)
93
+
94
+ print(result.nur_in_alt) # gelöschte OZ-Nummern
95
+ print(result.nur_in_neu) # neue OZ-Nummern
96
+ for pa in result.geaendert:
97
+ print(pa.oz, pa.aenderungen)
98
+ print(result.gesamtsumme_diff) # finanzielle Differenz
99
+
100
+ # XSD-Validierung
101
+ fehler = gaeb.validiere("ausschreibung.x83")
102
+ if fehler:
103
+ print(fehler)
104
+ ```
105
+
106
+ ## BoQ Builder
107
+
108
+ ```python
109
+ import gaeb
110
+
111
+ lv = (
112
+ gaeb.BoQBuilder(
113
+ phase=gaeb.Phase.ANGEBOTSAUFFORDERUNG,
114
+ titel_lv="Hochwasserschutz",
115
+ projekt="Testprojekt",
116
+ )
117
+ .titel("Erdarbeiten")
118
+ .position("Bodenaushub", einheit="m³", menge=250, ep="12.50")
119
+ .position("Bodentransport", einheit="m³", menge=250, ep="8.00")
120
+ .ende()
121
+ .titel("Betonarbeiten")
122
+ .untertitel("Fundamente")
123
+ .position("Streifenfundament", einheit="m³", menge=30, ep="185.00")
124
+ .ende()
125
+ .ende()
126
+ .build()
127
+ )
128
+
129
+ gaeb.write_xml(lv, "ausschreibung.x83")
130
+ ```
131
+
132
+ OZ-Generierung basiert auf dem `BoQBkdn`-Schema (Standard: 2+2+4 Zeichen):
133
+ - Titel: `01`, `02`, …
134
+ - Untertitel: `0101`, `0102`, …
135
+ - Position: `01000001`, `01010001`, …
136
+
137
+ ## Datenmodell
138
+
139
+ ```
140
+ Leistungsverzeichnis
141
+ ├── phase: Phase
142
+ ├── titel_lv, projekt, auftraggeber, auftragnehmer
143
+ ├── waehrung, xml_version, encoding
144
+ ├── vorbemerkungen: list[str]
145
+ ├── zeitvertrag_typ: str | None
146
+ ├── boq_bkdn: list[BoQBkdn]
147
+ ├── gesamtsumme: Decimal | None (property)
148
+ └── titel: list[Titel]
149
+ ├── nummer, kurztext, langtext
150
+ ├── positionen: list[Position]
151
+ │ ├── oz, kurztext, langtext
152
+ │ ├── menge, einheit, einheitspreis
153
+ │ ├── gesamtpreis (property: menge × EP)
154
+ │ ├── gesamtbetrag, mwst, nachlass_prozent
155
+ │ ├── pauschale, entfaellt, nicht_angeboten
156
+ │ ├── stundenlohn, schwerpunkt, provis
157
+ │ ├── typ: PositionTyp
158
+ │ ├── aln_gruppe, aln_nummer, ep_anteile
159
+ │ └── periodqty, min_menge, max_menge (Z-Phasen)
160
+ └── untertitel: list[Titel] (rekursiv)
161
+ ```
162
+
163
+ ## Unterstützte Phasen
164
+
165
+ | Bereich | Phasen |
166
+ |---------|--------|
167
+ | Mengenermittlung | 31 |
168
+ | Kostenermittlung | 50, 51, 52 |
169
+ | Vergabe (Procurement) | 80–89, 83Z, 84Z, 86ZR, 86ZE |
170
+ | Handel / Handwerk | 93–97 |
171
+
172
+ ## Optionale Abhängigkeiten
173
+
174
+ | Extra | Paket | Feature |
175
+ |-------|-------|---------|
176
+ | `gaeb[excel]` | openpyxl ≥ 3.1 | Excel-Export (.xlsx) |
177
+
178
+ ## Lizenz
179
+
180
+ MIT – siehe [LICENSE](../LICENSE)
gaeb-0.5.2/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # gaeb
2
+
3
+ Python-Bibliothek zum Lesen, Schreiben, Konvertieren und Vergleichen von **GAEB-Dateien** (AVA – Ausschreibung, Vergabe, Abrechnung im deutschen Bauwesen).
4
+
5
+ ## Features
6
+
7
+ - **GAEB DA XML 2.0–3.3** lesen und schreiben (automatische Versionserkennung, Multi-Version Writer)
8
+ - **GAEB 90** lesen und schreiben (`.d80`–`.d89`; Encoding-Autoerkennung)
9
+ - **GAEB 2000** lesen und schreiben (`.p80`–`.p89`)
10
+ - **Alle Austauschphasen**: Mengenermittlung (31), Kostenermittlung (50–52), Vergabe (80–89, 83Z, 84Z, 86ZR, 86ZE), Handel/Handwerk (93–97)
11
+ - **BoQ Builder**: programmatischer LV-Aufbau mit Auto-OZ-Generierung und Fluent API
12
+ - **Excel-Export** (.xlsx) mit Hierarchie-Layout — optional via `pip install gaeb[excel]`
13
+ - **Document Diff**: zwei LVs vergleichen, alle Felder prüfen, finanzielle Auswirkungen berechnen
14
+ - **XSD-Validierung** gegen offizielle GAEB-Schemas (Phasen 80–87)
15
+ - **Preisspiegel- & Raumbuch-Modell** für Angebotsvergleiche und räumliche Zuordnung
16
+ - **Security-Hardened**: XXE-Prevention, Billion-Laughs-Schutz, Dateigrössen-Limit, Rekursionstiefenbegrenzung
17
+ - Einheitliches **Pydantic v2** Datenmodell für alle Formate
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ pip install gaeb
23
+
24
+ # Mit Excel-Export
25
+ pip install gaeb[excel]
26
+ ```
27
+
28
+ ## Schnellstart
29
+
30
+ ```python
31
+ import gaeb
32
+
33
+ # Lesen
34
+ lv = gaeb.read_xml("ausschreibung.x83")
35
+ lv = gaeb.read_gaeb90("ausschreibung.d83")
36
+ lv = gaeb.read_gaeb2000("ausschreibung.p83")
37
+
38
+ # Metadaten
39
+ print(lv.titel_lv) # LV-Titel
40
+ print(lv.phase) # Phase.ANGEBOTSAUFFORDERUNG
41
+ print(lv.xml_version) # "3.3" (nur bei DA XML)
42
+ print(lv.encoding) # "cp850" (nur bei GAEB 90 / 2000)
43
+ print(lv.gesamtsumme) # Decimal oder None
44
+
45
+ # Positionen
46
+ for pos in lv.alle_positionen:
47
+ print(pos.oz, pos.kurztext, pos.menge, pos.einheit)
48
+
49
+ # Schreiben / Konvertieren
50
+ gaeb.write_xml(lv, "ausgabe.x83")
51
+ gaeb.write_xml(lv, "ausgabe_v32.x83", version="3.2") # explizite Version
52
+ gaeb.write_gaeb90(lv, "ausgabe.d83")
53
+ gaeb.write_gaeb2000(lv, "ausgabe.p83")
54
+
55
+ # Excel-Export
56
+ gaeb.write_excel(lv, "ausgabe.xlsx")
57
+ gaeb.write_excel(lv, "ausgabe.xlsx", langtext=True)
58
+
59
+ # Zwei LVs vergleichen
60
+ lv_neu = gaeb.read_xml("angebot.x84")
61
+ result = gaeb.vergleiche(lv, lv_neu)
62
+
63
+ print(result.nur_in_alt) # gelöschte OZ-Nummern
64
+ print(result.nur_in_neu) # neue OZ-Nummern
65
+ for pa in result.geaendert:
66
+ print(pa.oz, pa.aenderungen)
67
+ print(result.gesamtsumme_diff) # finanzielle Differenz
68
+
69
+ # XSD-Validierung
70
+ fehler = gaeb.validiere("ausschreibung.x83")
71
+ if fehler:
72
+ print(fehler)
73
+ ```
74
+
75
+ ## BoQ Builder
76
+
77
+ ```python
78
+ import gaeb
79
+
80
+ lv = (
81
+ gaeb.BoQBuilder(
82
+ phase=gaeb.Phase.ANGEBOTSAUFFORDERUNG,
83
+ titel_lv="Hochwasserschutz",
84
+ projekt="Testprojekt",
85
+ )
86
+ .titel("Erdarbeiten")
87
+ .position("Bodenaushub", einheit="m³", menge=250, ep="12.50")
88
+ .position("Bodentransport", einheit="m³", menge=250, ep="8.00")
89
+ .ende()
90
+ .titel("Betonarbeiten")
91
+ .untertitel("Fundamente")
92
+ .position("Streifenfundament", einheit="m³", menge=30, ep="185.00")
93
+ .ende()
94
+ .ende()
95
+ .build()
96
+ )
97
+
98
+ gaeb.write_xml(lv, "ausschreibung.x83")
99
+ ```
100
+
101
+ OZ-Generierung basiert auf dem `BoQBkdn`-Schema (Standard: 2+2+4 Zeichen):
102
+ - Titel: `01`, `02`, …
103
+ - Untertitel: `0101`, `0102`, …
104
+ - Position: `01000001`, `01010001`, …
105
+
106
+ ## Datenmodell
107
+
108
+ ```
109
+ Leistungsverzeichnis
110
+ ├── phase: Phase
111
+ ├── titel_lv, projekt, auftraggeber, auftragnehmer
112
+ ├── waehrung, xml_version, encoding
113
+ ├── vorbemerkungen: list[str]
114
+ ├── zeitvertrag_typ: str | None
115
+ ├── boq_bkdn: list[BoQBkdn]
116
+ ├── gesamtsumme: Decimal | None (property)
117
+ └── titel: list[Titel]
118
+ ├── nummer, kurztext, langtext
119
+ ├── positionen: list[Position]
120
+ │ ├── oz, kurztext, langtext
121
+ │ ├── menge, einheit, einheitspreis
122
+ │ ├── gesamtpreis (property: menge × EP)
123
+ │ ├── gesamtbetrag, mwst, nachlass_prozent
124
+ │ ├── pauschale, entfaellt, nicht_angeboten
125
+ │ ├── stundenlohn, schwerpunkt, provis
126
+ │ ├── typ: PositionTyp
127
+ │ ├── aln_gruppe, aln_nummer, ep_anteile
128
+ │ └── periodqty, min_menge, max_menge (Z-Phasen)
129
+ └── untertitel: list[Titel] (rekursiv)
130
+ ```
131
+
132
+ ## Unterstützte Phasen
133
+
134
+ | Bereich | Phasen |
135
+ |---------|--------|
136
+ | Mengenermittlung | 31 |
137
+ | Kostenermittlung | 50, 51, 52 |
138
+ | Vergabe (Procurement) | 80–89, 83Z, 84Z, 86ZR, 86ZE |
139
+ | Handel / Handwerk | 93–97 |
140
+
141
+ ## Optionale Abhängigkeiten
142
+
143
+ | Extra | Paket | Feature |
144
+ |-------|-------|---------|
145
+ | `gaeb[excel]` | openpyxl ≥ 3.1 | Excel-Export (.xlsx) |
146
+
147
+ ## Lizenz
148
+
149
+ MIT – siehe [LICENSE](../LICENSE)
@@ -0,0 +1,51 @@
1
+ [project]
2
+ name = "gaeb"
3
+ version = "0.5.2"
4
+ description = "Python library for reading, writing, converting and diffing GAEB files (AVA data exchange format, DA XML 2.0–3.3, GAEB 90, GAEB 2000)"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ authors = [
8
+ { name = "Attackwave", email = "attackwave@gmail.com" }
9
+ ]
10
+ keywords = ["gaeb", "ava", "construction", "leistungsverzeichnis", "bau", "gaeb90", "gaeb2000", "xml", "excel", "diff"]
11
+ classifiers = [
12
+ "Development Status :: 4 - Beta",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Programming Language :: Python :: 3.13",
20
+ "Topic :: Office/Business",
21
+ ]
22
+ requires-python = ">=3.10"
23
+ dependencies = [
24
+ "pydantic>=2.0",
25
+ "lxml>=4.9.4",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/Attackwave/gaeb-python"
30
+ Repository = "https://github.com/Attackwave/gaeb-python"
31
+ Issues = "https://github.com/Attackwave/gaeb-python/issues"
32
+ Changelog = "https://github.com/Attackwave/gaeb-python/blob/main/CHANGELOG.md"
33
+
34
+ [project.optional-dependencies]
35
+ dev = [
36
+ "pytest>=7.0",
37
+ "pytest-cov>=4.0",
38
+ ]
39
+ excel = [
40
+ "openpyxl>=3.1",
41
+ ]
42
+
43
+ [build-system]
44
+ requires = ["uv_build>=0.11.1,<0.12.0"]
45
+ build-backend = "uv_build"
46
+
47
+ [dependency-groups]
48
+ dev = [
49
+ "pytest>=9.0.2",
50
+ "pytest-cov>=7.1.0",
51
+ ]
@@ -0,0 +1,84 @@
1
+ """gaeb – Python library for reading and writing GAEB files (AVA).
2
+
3
+ Note on language
4
+ ----------------
5
+ GAEB is a German construction-industry standard (Gemeinsamer Ausschuss
6
+ Elektronik im Bauwesen). A mixed naming convention is used:
7
+
8
+ - **Methods and functions** use English names (``read_xml``, ``write_gaeb90``,
9
+ ``validate``, ``compare``).
10
+ - **Domain fields** on model classes use German identifiers that directly mirror
11
+ the official GAEB specification:
12
+
13
+ Leistungsverzeichnis – bill of quantities (BoQ)
14
+ Titel – section / chapter
15
+ Position – line item
16
+ Kurztext – short description
17
+ Langtext – long description
18
+ Einheit – unit of measure
19
+ Menge – quantity
20
+ Einheitspreis – unit price
21
+ Gesamtpreis – total price
22
+ Phase – exchange phase (e.g. 83 = tender, 84 = bid)
23
+ """
24
+
25
+ from .builder import BoQBuilder
26
+ from .diff import DiffResult, FieldChange, PositionChange, compare
27
+ from .io.excel.reader import read as read_excel
28
+ from .io.excel.writer import write as write_excel
29
+ from .io.gaeb90.reader import read as read_gaeb90
30
+ from .io.gaeb90.writer import write as write_gaeb90
31
+ from .io.gaeb2000.reader import read as read_gaeb2000
32
+ from .io.gaeb2000.writer import write as write_gaeb2000
33
+ from .io.xml.reader import read as read_xml
34
+ from .io.xml.validator import ValidationError, validate, validate_or_raise
35
+ from .io.xml.writer import write as write_xml
36
+ from .models import (
37
+ Bieter,
38
+ BieterEP,
39
+ BoQBkdn,
40
+ Leistungsverzeichnis,
41
+ Phase,
42
+ Position,
43
+ PositionTyp,
44
+ Preisspiegel,
45
+ Raum,
46
+ Raumbuch,
47
+ Raumgruppe,
48
+ RaumPosition,
49
+ Titel,
50
+ )
51
+
52
+ __all__ = [
53
+ "Bieter",
54
+ "BieterEP",
55
+ "BoQBkdn",
56
+ "BoQBuilder",
57
+ "DiffResult",
58
+ "FieldChange",
59
+ "Leistungsverzeichnis",
60
+ "Phase",
61
+ "Position",
62
+ "PositionChange",
63
+ "PositionTyp",
64
+ "Preisspiegel",
65
+ "Raum",
66
+ "RaumPosition",
67
+ "Raumbuch",
68
+ "Raumgruppe",
69
+ "Titel",
70
+ "ValidationError",
71
+ "compare",
72
+ "read_excel",
73
+ "read_gaeb90",
74
+ "read_gaeb2000",
75
+ "read_xml",
76
+ "validate",
77
+ "validate_or_raise",
78
+ "write_excel",
79
+ "write_gaeb90",
80
+ "write_gaeb2000",
81
+ "write_xml",
82
+ ]
83
+
84
+ __version__ = "0.5.2"