cbpr-usage-rules 0.3.0__tar.gz → 0.5.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.
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/CHANGELOG.md +20 -0
- {cbpr_usage_rules-0.3.0/src/cbpr_usage_rules.egg-info → cbpr_usage_rules-0.5.0}/PKG-INFO +28 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/README.md +27 -2
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/__init__.py +19 -1
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/cli.py +52 -2
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/engine.py +10 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/camt.052.max.xml +79 -79
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/camt.052.min.xml +1 -1
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/camt.054.max.xml +78 -78
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/camt.054.min.xml +1 -1
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2026 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2025}/pacs.002.max.xml +17 -17
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.002.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.004.max.xml +49 -49
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.004.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.008.max.xml +41 -41
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.008.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.008_stp.max.xml +41 -41
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.008_stp.min.xml +6 -6
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2026 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2025}/pacs.009.max.xml +37 -37
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2026 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2025}/pacs.009.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.009_adv.max.xml +41 -41
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2026 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2025}/pacs.009_adv.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.009_cov.max.xml +53 -53
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pacs.009_cov.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2025/pain.001.max.xml +28 -28
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2026 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2025}/pain.001.min.xml +2 -2
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/camt.052.max.xml +79 -79
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/camt.052.min.xml +1 -1
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/camt.054.max.xml +78 -78
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/camt.054.min.xml +1 -1
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2025 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2026}/pacs.002.max.xml +17 -17
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.002.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.004.max.xml +45 -45
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.004.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.008.max.xml +41 -41
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.008.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.008_stp.max.xml +41 -41
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.008_stp.min.xml +6 -6
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2025 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2026}/pacs.009.max.xml +37 -37
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2025 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2026}/pacs.009.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.009_adv.max.xml +41 -41
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2025 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2026}/pacs.009_adv.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.009_cov.max.xml +53 -53
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pacs.009_cov.min.xml +3 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/examples/y2026/pain.001.max.xml +27 -27
- {cbpr_usage_rules-0.3.0/src/cbpr_rules/examples/y2025 → cbpr_usage_rules-0.5.0/src/cbpr_rules/examples/y2026}/pain.001.min.xml +2 -2
- cbpr_usage_rules-0.5.0/src/cbpr_rules/idgen.py +243 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0/src/cbpr_usage_rules.egg-info}/PKG-INFO +28 -3
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_usage_rules.egg-info/SOURCES.txt +3 -1
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/tests/test_examples.py +24 -8
- cbpr_usage_rules-0.5.0/tests/test_idgen.py +79 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/LICENSE +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/MANIFEST.in +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/pyproject.toml +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/setup.cfg +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/helpers.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/loader.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/message.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/models.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/py.typed +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/reference/__init__.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/reference/countries.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/reference/currencies.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/registry.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/__init__.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/__init__.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/camt_052.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/camt_054.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/pacs_002.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/pacs_004.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/pacs_008.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/pacs_008_stp.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/pacs_009.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/pacs_009_adv.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/pacs_009_cov.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2025/pain_001.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/__init__.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/camt_052.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/camt_054.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/pacs_002.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/pacs_004.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/pacs_008.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/pacs_008_stp.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/pacs_009.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/pacs_009_adv.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/pacs_009_cov.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/rules/y2026/pain_001.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/schema.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/validators/__init__.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/validators/bic.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/validators/country.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/validators/currency.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/validators/iban.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_rules/validators/lei.py +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_usage_rules.egg-info/dependency_links.txt +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_usage_rules.egg-info/entry_points.txt +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_usage_rules.egg-info/requires.txt +0 -0
- {cbpr_usage_rules-0.3.0 → cbpr_usage_rules-0.5.0}/src/cbpr_usage_rules.egg-info/top_level.txt +0 -0
|
@@ -4,6 +4,26 @@ All notable changes to this project are documented here. The format is based on
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
|
|
5
5
|
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.5.0]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Deterministic **ID generation** library (`cbpr_rules.idgen`, "Counting Strings"
|
|
11
|
+
algorithm — no `random`/`uuid`): `generate_iban`, `generate_lei`, `generate_bic`,
|
|
12
|
+
`generate_uuid`/`generate_uetr`, `generate_mid`, plus `counting_string`/
|
|
13
|
+
`counting_sequence` and seeded helpers. Every id is structurally valid and passes
|
|
14
|
+
the package's own validators; same seed → same output. New CLI
|
|
15
|
+
`cbpr-validate --generate {iban,lei,bic,uuid,uetr,mid,text}` (with
|
|
16
|
+
`--seed/--country/--bank/--branch/--count`). The bundled example messages now
|
|
17
|
+
source their identifiers from this library (seeded per example).
|
|
18
|
+
|
|
19
|
+
## [0.4.0]
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- List only the **enforceable** rules for a year + message type:
|
|
23
|
+
`list_rules(year, msgtype, enforced_only=True)` in the API and
|
|
24
|
+
`cbpr-validate --enforced --year … --type …` on the CLI (advisory rules omitted;
|
|
25
|
+
composes with `--json`).
|
|
26
|
+
|
|
7
27
|
## [0.3.0]
|
|
8
28
|
|
|
9
29
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cbpr-usage-rules
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Validate ISO 20022 CBPR+ XML messages against SWIFT usage (business) rules.
|
|
5
5
|
Author: Pete Houghton
|
|
6
6
|
License: MIT License
|
|
@@ -172,11 +172,34 @@ xml = cbpr_rules.example_message(2025, "pacs.008", "max") # variant defaults t
|
|
|
172
172
|
cbpr_rules.example_variants(2025, "pacs.008") # ['min', 'max']
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
The data is **fictitious** (synthetic BICs/IBANs/LEIs
|
|
175
|
+
The data is **fictitious** (synthetic, generated BICs/IBANs/LEIs) and does
|
|
176
176
|
not reproduce any real sample — use them as starting templates, not real payments.
|
|
177
177
|
|
|
178
178
|
---
|
|
179
179
|
|
|
180
|
+
## Generating identifiers
|
|
181
|
+
|
|
182
|
+
The example values above are produced by a small **deterministic** ID generator
|
|
183
|
+
(the "Counting Strings" algorithm — no `random`/`uuid`, same seed → same output).
|
|
184
|
+
Every generated id is structurally valid and passes the tool's own validators.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
cbpr-validate --generate iban --country AT --seed s1 # ISO 13616 + mod-97
|
|
188
|
+
cbpr-validate --generate lei --seed acme # ISO 17442 + check digits
|
|
189
|
+
cbpr-validate --generate bic --bank JSBP --country GB # -> JSBPGB..XXX
|
|
190
|
+
cbpr-validate --generate uuid --count 3 # RFC 4122 v4 (UETR)
|
|
191
|
+
cbpr-validate --generate mid --country GB # message identifier
|
|
192
|
+
```
|
|
193
|
+
```python
|
|
194
|
+
from cbpr_rules import generate_iban, generate_lei, generate_bic, generate_uetr
|
|
195
|
+
generate_iban("DE", seed="acme") # deterministic, valid German IBAN
|
|
196
|
+
generate_bic(country="GB", seed="acme")
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
IBAN generation supports the 27 EU countries plus GB.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
180
203
|
## The result object
|
|
181
204
|
|
|
182
205
|
Both `validate_file` and `validate_string` return a dictionary:
|
|
@@ -258,11 +281,13 @@ matching is by local name, so namespace prefixes never matter.
|
|
|
258
281
|
```python
|
|
259
282
|
cbpr_rules.available(2025) # -> ['camt.052', 'pacs.008', ...]
|
|
260
283
|
cbpr_rules.list_rules(2025, "pacs.008") # -> [{rule_number, name, description, severity, enforced}, ...]
|
|
284
|
+
cbpr_rules.list_rules(2025, "pacs.008", enforced_only=True) # only the enforceable rules
|
|
261
285
|
```
|
|
262
286
|
|
|
263
287
|
```bash
|
|
264
288
|
cbpr-validate --year 2025 --list-types
|
|
265
|
-
cbpr-validate --year 2025 --type pacs.008 --list
|
|
289
|
+
cbpr-validate --year 2025 --type pacs.008 --list # all rules
|
|
290
|
+
cbpr-validate --year 2025 --type pacs.008 --enforced # enforceable rules only
|
|
266
291
|
```
|
|
267
292
|
|
|
268
293
|
### Algorithmic field validation
|
|
@@ -117,11 +117,34 @@ xml = cbpr_rules.example_message(2025, "pacs.008", "max") # variant defaults t
|
|
|
117
117
|
cbpr_rules.example_variants(2025, "pacs.008") # ['min', 'max']
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
The data is **fictitious** (synthetic BICs/IBANs/LEIs
|
|
120
|
+
The data is **fictitious** (synthetic, generated BICs/IBANs/LEIs) and does
|
|
121
121
|
not reproduce any real sample — use them as starting templates, not real payments.
|
|
122
122
|
|
|
123
123
|
---
|
|
124
124
|
|
|
125
|
+
## Generating identifiers
|
|
126
|
+
|
|
127
|
+
The example values above are produced by a small **deterministic** ID generator
|
|
128
|
+
(the "Counting Strings" algorithm — no `random`/`uuid`, same seed → same output).
|
|
129
|
+
Every generated id is structurally valid and passes the tool's own validators.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
cbpr-validate --generate iban --country AT --seed s1 # ISO 13616 + mod-97
|
|
133
|
+
cbpr-validate --generate lei --seed acme # ISO 17442 + check digits
|
|
134
|
+
cbpr-validate --generate bic --bank JSBP --country GB # -> JSBPGB..XXX
|
|
135
|
+
cbpr-validate --generate uuid --count 3 # RFC 4122 v4 (UETR)
|
|
136
|
+
cbpr-validate --generate mid --country GB # message identifier
|
|
137
|
+
```
|
|
138
|
+
```python
|
|
139
|
+
from cbpr_rules import generate_iban, generate_lei, generate_bic, generate_uetr
|
|
140
|
+
generate_iban("DE", seed="acme") # deterministic, valid German IBAN
|
|
141
|
+
generate_bic(country="GB", seed="acme")
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
IBAN generation supports the 27 EU countries plus GB.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
125
148
|
## The result object
|
|
126
149
|
|
|
127
150
|
Both `validate_file` and `validate_string` return a dictionary:
|
|
@@ -203,11 +226,13 @@ matching is by local name, so namespace prefixes never matter.
|
|
|
203
226
|
```python
|
|
204
227
|
cbpr_rules.available(2025) # -> ['camt.052', 'pacs.008', ...]
|
|
205
228
|
cbpr_rules.list_rules(2025, "pacs.008") # -> [{rule_number, name, description, severity, enforced}, ...]
|
|
229
|
+
cbpr_rules.list_rules(2025, "pacs.008", enforced_only=True) # only the enforceable rules
|
|
206
230
|
```
|
|
207
231
|
|
|
208
232
|
```bash
|
|
209
233
|
cbpr-validate --year 2025 --list-types
|
|
210
|
-
cbpr-validate --year 2025 --type pacs.008 --list
|
|
234
|
+
cbpr-validate --year 2025 --type pacs.008 --list # all rules
|
|
235
|
+
cbpr-validate --year 2025 --type pacs.008 --enforced # enforceable rules only
|
|
211
236
|
```
|
|
212
237
|
|
|
213
238
|
### Algorithmic field validation
|
|
@@ -4,7 +4,7 @@ This package is AI generated. See the README for details and caveats.
|
|
|
4
4
|
"""
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
-
__version__ = "0.
|
|
7
|
+
__version__ = "0.5.0"
|
|
8
8
|
|
|
9
9
|
from .models import Rule, Severity, Violation
|
|
10
10
|
from .engine import (
|
|
@@ -15,6 +15,16 @@ from .engine import (
|
|
|
15
15
|
example_message,
|
|
16
16
|
example_variants,
|
|
17
17
|
)
|
|
18
|
+
from .idgen import (
|
|
19
|
+
generate_iban,
|
|
20
|
+
generate_lei,
|
|
21
|
+
generate_bic,
|
|
22
|
+
generate_uuid,
|
|
23
|
+
generate_uetr,
|
|
24
|
+
generate_mid,
|
|
25
|
+
counting_string,
|
|
26
|
+
counting_sequence,
|
|
27
|
+
)
|
|
18
28
|
|
|
19
29
|
__all__ = [
|
|
20
30
|
"__version__",
|
|
@@ -27,4 +37,12 @@ __all__ = [
|
|
|
27
37
|
"available",
|
|
28
38
|
"example_message",
|
|
29
39
|
"example_variants",
|
|
40
|
+
"generate_iban",
|
|
41
|
+
"generate_lei",
|
|
42
|
+
"generate_bic",
|
|
43
|
+
"generate_uuid",
|
|
44
|
+
"generate_uetr",
|
|
45
|
+
"generate_mid",
|
|
46
|
+
"counting_string",
|
|
47
|
+
"counting_sequence",
|
|
30
48
|
]
|
|
@@ -9,6 +9,7 @@ import textwrap
|
|
|
9
9
|
from typing import List, Optional
|
|
10
10
|
|
|
11
11
|
from . import __version__
|
|
12
|
+
from . import idgen
|
|
12
13
|
from .engine import (
|
|
13
14
|
ValidationError,
|
|
14
15
|
available,
|
|
@@ -19,6 +20,29 @@ from .engine import (
|
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
|
|
23
|
+
def _generate(args) -> List[str]:
|
|
24
|
+
"""Produce the ``--generate`` output lines (one id per --count)."""
|
|
25
|
+
kind = args.generate
|
|
26
|
+
out: List[str] = []
|
|
27
|
+
for i in range(max(args.count, 1)):
|
|
28
|
+
seed = f"{args.seed}:{i}" if args.count > 1 else args.seed
|
|
29
|
+
if kind == "iban":
|
|
30
|
+
if not args.country:
|
|
31
|
+
raise ValueError("--generate iban requires --country (e.g. --country AT)")
|
|
32
|
+
out.append(idgen.generate_iban(args.country, seed))
|
|
33
|
+
elif kind == "lei":
|
|
34
|
+
out.append(idgen.generate_lei(seed))
|
|
35
|
+
elif kind == "bic":
|
|
36
|
+
out.append(idgen.generate_bic(args.bank, args.country or "GB", args.branch, seed))
|
|
37
|
+
elif kind in ("uuid", "uetr"):
|
|
38
|
+
out.append(idgen.generate_uuid(idgen.deterministic_int(seed or str(i), 0, 2**63)))
|
|
39
|
+
elif kind == "mid":
|
|
40
|
+
out.append(idgen.generate_mid("CBPR", args.country or "GB", i + 1))
|
|
41
|
+
elif kind == "text":
|
|
42
|
+
out.append(idgen.deterministic_string(seed or "text", 16))
|
|
43
|
+
return out
|
|
44
|
+
|
|
45
|
+
|
|
22
46
|
def _build_parser() -> argparse.ArgumentParser:
|
|
23
47
|
p = argparse.ArgumentParser(
|
|
24
48
|
prog="cbpr-validate",
|
|
@@ -72,11 +96,28 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
72
96
|
help="Root element tag wrapping the AppHdr+Document in --example output "
|
|
73
97
|
"(default: Envelope).",
|
|
74
98
|
)
|
|
99
|
+
p.add_argument(
|
|
100
|
+
"--generate",
|
|
101
|
+
choices=("iban", "lei", "bic", "uuid", "uetr", "mid", "text"),
|
|
102
|
+
help="Generate a deterministic, structurally-valid identifier and print it "
|
|
103
|
+
"(use --seed/--country/--bank/--branch/--count to control output).",
|
|
104
|
+
)
|
|
105
|
+
p.add_argument("--seed", default="", help="Seed for --generate (same seed -> same output).")
|
|
106
|
+
p.add_argument("--country", help="Country code for --generate iban/bic/mid (e.g. AT, GB).")
|
|
107
|
+
p.add_argument("--bank", help="Bank code for --generate bic (4 letters, padded with X).")
|
|
108
|
+
p.add_argument("--branch", default="XXX", help="Branch code for --generate bic (default XXX).")
|
|
109
|
+
p.add_argument("--count", type=int, default=1, help="How many ids to generate (default 1).")
|
|
75
110
|
p.add_argument(
|
|
76
111
|
"--list",
|
|
77
112
|
action="store_true",
|
|
78
113
|
help="List the rules for --year/--type instead of validating.",
|
|
79
114
|
)
|
|
115
|
+
p.add_argument(
|
|
116
|
+
"--enforced",
|
|
117
|
+
action="store_true",
|
|
118
|
+
help="List only the enforceable (mechanically-checked) rules for --year/--type; "
|
|
119
|
+
"advisory rules are omitted. Implies --list.",
|
|
120
|
+
)
|
|
80
121
|
p.add_argument(
|
|
81
122
|
"--list-types", action="store_true", help="List message types available for --year."
|
|
82
123
|
)
|
|
@@ -205,6 +246,15 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|
|
205
246
|
print(json.dumps(types) if args.json else "\n".join(types))
|
|
206
247
|
return 0
|
|
207
248
|
|
|
249
|
+
if args.generate:
|
|
250
|
+
try:
|
|
251
|
+
for line in _generate(args):
|
|
252
|
+
print(line)
|
|
253
|
+
except (ValueError, ValidationError) as exc:
|
|
254
|
+
print(f"error: {exc}", file=sys.stderr)
|
|
255
|
+
return 2
|
|
256
|
+
return 0
|
|
257
|
+
|
|
208
258
|
if args.example:
|
|
209
259
|
if args.year is None or args.msgtype is None:
|
|
210
260
|
print("error: --example requires --year and --type", file=sys.stderr)
|
|
@@ -216,11 +266,11 @@ def main(argv: Optional[List[str]] = None) -> int:
|
|
|
216
266
|
return 2
|
|
217
267
|
return 0
|
|
218
268
|
|
|
219
|
-
if args.list:
|
|
269
|
+
if args.list or args.enforced:
|
|
220
270
|
if args.year is None or args.msgtype is None:
|
|
221
271
|
print("error: --year and --type are required for --list", file=sys.stderr)
|
|
222
272
|
return 2
|
|
223
|
-
rules = list_rules(args.year, args.msgtype)
|
|
273
|
+
rules = list_rules(args.year, args.msgtype, enforced_only=args.enforced)
|
|
224
274
|
if args.json:
|
|
225
275
|
print(json.dumps(rules, indent=2))
|
|
226
276
|
else:
|
|
@@ -95,9 +95,16 @@ def validate_string(xml: str, year: int, msgtype: Optional[str] = None, xsd=None
|
|
|
95
95
|
return _validate_tree(tree, year, msgtype, xsd)
|
|
96
96
|
|
|
97
97
|
|
|
98
|
-
def list_rules(year: int, msgtype: str) -> List[dict]:
|
|
99
|
-
"""Return metadata for
|
|
100
|
-
|
|
98
|
+
def list_rules(year: int, msgtype: str, enforced_only: bool = False) -> List[dict]:
|
|
99
|
+
"""Return metadata for the rules registered for a (year, message type).
|
|
100
|
+
|
|
101
|
+
With ``enforced_only=True`` only the enforceable (mechanically-checked) rules
|
|
102
|
+
are returned, omitting advisory/catalogue-only ones.
|
|
103
|
+
"""
|
|
104
|
+
rules = [r.to_dict() for r in load_rules(year, msgtype)]
|
|
105
|
+
if enforced_only:
|
|
106
|
+
rules = [r for r in rules if r["enforced"]]
|
|
107
|
+
return rules
|
|
101
108
|
|
|
102
109
|
|
|
103
110
|
def available(year: int) -> List[str]:
|