xmlvalid 1.0.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.
- xmlvalid-1.0.0/.gitignore +8 -0
- xmlvalid-1.0.0/CHANGELOG.md +7 -0
- xmlvalid-1.0.0/LICENSE +21 -0
- xmlvalid-1.0.0/PKG-INFO +199 -0
- xmlvalid-1.0.0/README.md +175 -0
- xmlvalid-1.0.0/pyproject.toml +55 -0
- xmlvalid-1.0.0/src/xmlvalid/__init__.py +54 -0
- xmlvalid-1.0.0/src/xmlvalid/_client.py +638 -0
- xmlvalid-1.0.0/src/xmlvalid/_version.py +1 -0
- xmlvalid-1.0.0/src/xmlvalid/errors.py +103 -0
- xmlvalid-1.0.0/src/xmlvalid/models.py +358 -0
- xmlvalid-1.0.0/src/xmlvalid/py.typed +0 -0
- xmlvalid-1.0.0/src/xmlvalid/webhooks.py +56 -0
- xmlvalid-1.0.0/tests/__init__.py +0 -0
- xmlvalid-1.0.0/tests/conftest.py +121 -0
- xmlvalid-1.0.0/tests/fixtures/invoice.xml +210 -0
- xmlvalid-1.0.0/tests/fixtures/invoice.xsd +2 -0
- xmlvalid-1.0.0/tests/fixtures/main.sch +3 -0
- xmlvalid-1.0.0/tests/fixtures/totals.sch +1 -0
- xmlvalid-1.0.0/tests/test_async.py +63 -0
- xmlvalid-1.0.0/tests/test_client.py +288 -0
- xmlvalid-1.0.0/tests/test_webhooks.py +73 -0
xmlvalid-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 xmlvalid.com
|
|
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.
|
xmlvalid-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: xmlvalid
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python client for the xmlvalid API: validate XML and e-invoices (Peppol, XRechnung, Factur-X, UBL, CII) against XSD, DTD, RelaxNG and Schematron business rules
|
|
5
|
+
Project-URL: Homepage, https://xmlvalid.com
|
|
6
|
+
Project-URL: Documentation, https://xmlvalid.com/docs/api
|
|
7
|
+
Project-URL: Source, https://github.com/xmlvalid/xmlvalid-python
|
|
8
|
+
Project-URL: Issues, https://github.com/xmlvalid/xmlvalid-python/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/xmlvalid/xmlvalid-python/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: xmlvalid <support@xmlvalid.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: e-invoice,en16931,factur-x,peppol,schematron,ubl,validation,xml,xrechnung,xsd
|
|
14
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Requires-Dist: httpx<1,>=0.27
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# xmlvalid for Python
|
|
26
|
+
|
|
27
|
+
Python client for the [xmlvalid API](https://xmlvalid.com/docs/api): validate XML documents and
|
|
28
|
+
e-invoices against XSD, DTD, RelaxNG and Schematron business rules. Peppol BIS, XRechnung,
|
|
29
|
+
Factur-X / ZUGFeRD, EN 16931, UBL, CII and national rules (France, Italy, Croatia, Romania and
|
|
30
|
+
more) are in the [schema catalog](https://xmlvalid.com/schemas); your own schemas work too.
|
|
31
|
+
|
|
32
|
+
- Python 3.10+, sync and async (asyncio, trio), built on [httpx](https://www.python-httpx.org)
|
|
33
|
+
- Large files are streamed, not loaded into memory
|
|
34
|
+
- Waits for the result for you, retries when rate limited
|
|
35
|
+
- Typed results and exceptions, webhook signature checks
|
|
36
|
+
|
|
37
|
+
## Install
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install xmlvalid
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Create an API key under [Dashboard → API keys](https://xmlvalid.com/dashboard/api).
|
|
44
|
+
|
|
45
|
+
## Validate
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from xmlvalid import Client
|
|
49
|
+
|
|
50
|
+
xmlvalid = Client("xv_…") # or set XMLVALID_API_KEY
|
|
51
|
+
|
|
52
|
+
validation = xmlvalid.validate("invoice.xml", schema="peppol-bis-3-invoice")
|
|
53
|
+
|
|
54
|
+
if validation.is_valid:
|
|
55
|
+
print("Valid")
|
|
56
|
+
else:
|
|
57
|
+
for error in validation.errors:
|
|
58
|
+
print(error) # Line 139: [BR-CO-16] Amount due for payment (BT-115) = …
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The document can be:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
xmlvalid.validate("invoice.xml") # a path (XML, .gz, .zip, EPUB, Factur-X PDF)
|
|
65
|
+
xmlvalid.validate(Path("invoice.xml")) # a Path
|
|
66
|
+
xmlvalid.validate(data, name="invoice.xml") # bytes
|
|
67
|
+
xmlvalid.validate(open("invoice.xml", "rb")) # a binary file object
|
|
68
|
+
xmlvalid.validate(text="<Invoice>…</Invoice>") # a string
|
|
69
|
+
xmlvalid.validate(url="https://example.com/feed.xml") # a public URL, downloaded by xmlvalid
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The schema:
|
|
73
|
+
|
|
74
|
+
| Argument | Validates against |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `schema="peppol-bis-3-invoice"` | A [catalog](https://xmlvalid.com/schemas) entry, with its business rules |
|
|
77
|
+
| `schema="auto"` | The catalog profile an e-invoice names (BT-24), for mixed invoices |
|
|
78
|
+
| `schema="my-12"` | One of your saved schemas |
|
|
79
|
+
| `schema_file="order.xsd"` | An XSD, DTD or RelaxNG file sent with the document |
|
|
80
|
+
| `doctype=True` | The DOCTYPE the document declares |
|
|
81
|
+
| none | Well-formedness only |
|
|
82
|
+
|
|
83
|
+
Your own Schematron runs after the schema check: `rules="rules.sch"`, or for rules with
|
|
84
|
+
includes, relative path: file: `rules={"main.sch": "/path/main.sch", "parts/totals.sch": "/path/parts/totals.sch"}`.
|
|
85
|
+
|
|
86
|
+
## Async
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from xmlvalid import AsyncClient
|
|
90
|
+
|
|
91
|
+
async with AsyncClient() as xmlvalid:
|
|
92
|
+
validation = await xmlvalid.validate("invoice.xml", schema="xrechnung-3-ubl")
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Every method of `Client` is there, awaited.
|
|
96
|
+
|
|
97
|
+
## The result
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
validation.status # done, failed (on xmlvalid's side) or cancelled
|
|
101
|
+
validation.result.outcome # valid, warnings, invalid, schema, input or failed
|
|
102
|
+
validation.result.errors_total # all of them; the first 500 are listed
|
|
103
|
+
for error in validation.errors:
|
|
104
|
+
error.line, error.column, error.level, error.type # xsd, schematron, …
|
|
105
|
+
error.rule # BR-CO-16 for a business rule
|
|
106
|
+
error.message
|
|
107
|
+
error.rule_url # the rule's page on xmlvalid.com
|
|
108
|
+
error.help_url # how to fix this kind of error
|
|
109
|
+
validation.warnings
|
|
110
|
+
validation.raw # the API's JSON, as a dict
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For a .zip, `validation.result.items` has one result per document; for a PDF,
|
|
114
|
+
`validation.result.pdf` names the invoice found in it.
|
|
115
|
+
|
|
116
|
+
## Long validations, reports and the account
|
|
117
|
+
|
|
118
|
+
`validate()` waits up to 15 minutes (`timeout=`); a `ValidationTimeoutError` carries the
|
|
119
|
+
validation, which goes on on the server. To queue and come back later:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
validation = xmlvalid.submit("big.xml", schema="ubl-2.1-invoice")
|
|
123
|
+
# …
|
|
124
|
+
validation = xmlvalid.wait_for(validation.id) # or xmlvalid.validation(id), xmlvalid.cancel(id)
|
|
125
|
+
|
|
126
|
+
html = xmlvalid.report(validation) # the HTML report
|
|
127
|
+
link = xmlvalid.share([validation]) # a public link for 30 days (Pro): link.url
|
|
128
|
+
|
|
129
|
+
usage = xmlvalid.usage() # usage.used, usage.limit, usage.remaining
|
|
130
|
+
schemas = xmlvalid.schemas() # your saved schemas, then the catalog
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Errors
|
|
134
|
+
|
|
135
|
+
Every exception extends `xmlvalid.XmlvalidError`. API refusals are `ApiError`s with
|
|
136
|
+
`status_code`, `error_code` and, for `invalid_request`, `fields`:
|
|
137
|
+
|
|
138
|
+
| Exception | When |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `AuthenticationError` | 401: no key, a revoked key |
|
|
141
|
+
| `PlanLimitError` | 403: not in your plan |
|
|
142
|
+
| `NotFoundError` | 404: no such validation, or it expired (24 hours) |
|
|
143
|
+
| `NotFinishedError` | 409: the report of a validation still running |
|
|
144
|
+
| `DocumentTooLargeError` | 413: over your plan's size limit |
|
|
145
|
+
| `InvalidRequestError` | 422: unknown schema, a bad URL, … |
|
|
146
|
+
| `QuotaExceededError` | 429: this month's validations are used up |
|
|
147
|
+
| `RateLimitedError` | 429: still limited after the retries; `retry_after` seconds |
|
|
148
|
+
| `ServerError` | 5xx |
|
|
149
|
+
| `TransportError` | The request could not be sent or its answer read |
|
|
150
|
+
| `ValidationTimeoutError` | Still running after `timeout=` (also a `TimeoutError`) |
|
|
151
|
+
|
|
152
|
+
## Webhooks
|
|
153
|
+
|
|
154
|
+
On Pro, xmlvalid can call your endpoint when a validation finishes or a URL monitor changes
|
|
155
|
+
state. Check the signature with the endpoint's secret and the raw body:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from xmlvalid import Event, webhooks
|
|
159
|
+
|
|
160
|
+
event = webhooks.verify(
|
|
161
|
+
request.body, # the raw bytes, as received
|
|
162
|
+
request.headers.get("Xmlvalid-Signature"),
|
|
163
|
+
os.environ["XMLVALID_WEBHOOK_SECRET"],
|
|
164
|
+
) # raises SignatureVerificationError
|
|
165
|
+
|
|
166
|
+
if event.type == Event.VALIDATION_COMPLETED:
|
|
167
|
+
validation = event.validation
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
A retried delivery has the same `event.id`. The other events are `monitor.failed`,
|
|
171
|
+
`monitor.recovered` (`event.data["monitor"]`, `event.data["check"]`) and `ping`.
|
|
172
|
+
|
|
173
|
+
## Options
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
Client(
|
|
177
|
+
api_key="xv_…", # default: XMLVALID_API_KEY
|
|
178
|
+
base_url="https://xmlvalid.com/api/v1",
|
|
179
|
+
timeout=900, # seconds validate() waits in all
|
|
180
|
+
wait=10, # seconds the API holds a new request (0-60)
|
|
181
|
+
max_retries=3, # retries of a 429 rate_limited
|
|
182
|
+
http_client=httpx.Client(...), # proxies, certificates, a mock transport in tests
|
|
183
|
+
)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Use it as a context manager, or call `close()`, to close the connection pool.
|
|
187
|
+
|
|
188
|
+
## Development
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
uv sync
|
|
192
|
+
uv run pytest
|
|
193
|
+
uv run mypy
|
|
194
|
+
uv run ruff check && uv run ruff format --check
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## License
|
|
198
|
+
|
|
199
|
+
MIT
|
xmlvalid-1.0.0/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# xmlvalid for Python
|
|
2
|
+
|
|
3
|
+
Python client for the [xmlvalid API](https://xmlvalid.com/docs/api): validate XML documents and
|
|
4
|
+
e-invoices against XSD, DTD, RelaxNG and Schematron business rules. Peppol BIS, XRechnung,
|
|
5
|
+
Factur-X / ZUGFeRD, EN 16931, UBL, CII and national rules (France, Italy, Croatia, Romania and
|
|
6
|
+
more) are in the [schema catalog](https://xmlvalid.com/schemas); your own schemas work too.
|
|
7
|
+
|
|
8
|
+
- Python 3.10+, sync and async (asyncio, trio), built on [httpx](https://www.python-httpx.org)
|
|
9
|
+
- Large files are streamed, not loaded into memory
|
|
10
|
+
- Waits for the result for you, retries when rate limited
|
|
11
|
+
- Typed results and exceptions, webhook signature checks
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install xmlvalid
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Create an API key under [Dashboard → API keys](https://xmlvalid.com/dashboard/api).
|
|
20
|
+
|
|
21
|
+
## Validate
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from xmlvalid import Client
|
|
25
|
+
|
|
26
|
+
xmlvalid = Client("xv_…") # or set XMLVALID_API_KEY
|
|
27
|
+
|
|
28
|
+
validation = xmlvalid.validate("invoice.xml", schema="peppol-bis-3-invoice")
|
|
29
|
+
|
|
30
|
+
if validation.is_valid:
|
|
31
|
+
print("Valid")
|
|
32
|
+
else:
|
|
33
|
+
for error in validation.errors:
|
|
34
|
+
print(error) # Line 139: [BR-CO-16] Amount due for payment (BT-115) = …
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The document can be:
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
xmlvalid.validate("invoice.xml") # a path (XML, .gz, .zip, EPUB, Factur-X PDF)
|
|
41
|
+
xmlvalid.validate(Path("invoice.xml")) # a Path
|
|
42
|
+
xmlvalid.validate(data, name="invoice.xml") # bytes
|
|
43
|
+
xmlvalid.validate(open("invoice.xml", "rb")) # a binary file object
|
|
44
|
+
xmlvalid.validate(text="<Invoice>…</Invoice>") # a string
|
|
45
|
+
xmlvalid.validate(url="https://example.com/feed.xml") # a public URL, downloaded by xmlvalid
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The schema:
|
|
49
|
+
|
|
50
|
+
| Argument | Validates against |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `schema="peppol-bis-3-invoice"` | A [catalog](https://xmlvalid.com/schemas) entry, with its business rules |
|
|
53
|
+
| `schema="auto"` | The catalog profile an e-invoice names (BT-24), for mixed invoices |
|
|
54
|
+
| `schema="my-12"` | One of your saved schemas |
|
|
55
|
+
| `schema_file="order.xsd"` | An XSD, DTD or RelaxNG file sent with the document |
|
|
56
|
+
| `doctype=True` | The DOCTYPE the document declares |
|
|
57
|
+
| none | Well-formedness only |
|
|
58
|
+
|
|
59
|
+
Your own Schematron runs after the schema check: `rules="rules.sch"`, or for rules with
|
|
60
|
+
includes, relative path: file: `rules={"main.sch": "/path/main.sch", "parts/totals.sch": "/path/parts/totals.sch"}`.
|
|
61
|
+
|
|
62
|
+
## Async
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from xmlvalid import AsyncClient
|
|
66
|
+
|
|
67
|
+
async with AsyncClient() as xmlvalid:
|
|
68
|
+
validation = await xmlvalid.validate("invoice.xml", schema="xrechnung-3-ubl")
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Every method of `Client` is there, awaited.
|
|
72
|
+
|
|
73
|
+
## The result
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
validation.status # done, failed (on xmlvalid's side) or cancelled
|
|
77
|
+
validation.result.outcome # valid, warnings, invalid, schema, input or failed
|
|
78
|
+
validation.result.errors_total # all of them; the first 500 are listed
|
|
79
|
+
for error in validation.errors:
|
|
80
|
+
error.line, error.column, error.level, error.type # xsd, schematron, …
|
|
81
|
+
error.rule # BR-CO-16 for a business rule
|
|
82
|
+
error.message
|
|
83
|
+
error.rule_url # the rule's page on xmlvalid.com
|
|
84
|
+
error.help_url # how to fix this kind of error
|
|
85
|
+
validation.warnings
|
|
86
|
+
validation.raw # the API's JSON, as a dict
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
For a .zip, `validation.result.items` has one result per document; for a PDF,
|
|
90
|
+
`validation.result.pdf` names the invoice found in it.
|
|
91
|
+
|
|
92
|
+
## Long validations, reports and the account
|
|
93
|
+
|
|
94
|
+
`validate()` waits up to 15 minutes (`timeout=`); a `ValidationTimeoutError` carries the
|
|
95
|
+
validation, which goes on on the server. To queue and come back later:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
validation = xmlvalid.submit("big.xml", schema="ubl-2.1-invoice")
|
|
99
|
+
# …
|
|
100
|
+
validation = xmlvalid.wait_for(validation.id) # or xmlvalid.validation(id), xmlvalid.cancel(id)
|
|
101
|
+
|
|
102
|
+
html = xmlvalid.report(validation) # the HTML report
|
|
103
|
+
link = xmlvalid.share([validation]) # a public link for 30 days (Pro): link.url
|
|
104
|
+
|
|
105
|
+
usage = xmlvalid.usage() # usage.used, usage.limit, usage.remaining
|
|
106
|
+
schemas = xmlvalid.schemas() # your saved schemas, then the catalog
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Errors
|
|
110
|
+
|
|
111
|
+
Every exception extends `xmlvalid.XmlvalidError`. API refusals are `ApiError`s with
|
|
112
|
+
`status_code`, `error_code` and, for `invalid_request`, `fields`:
|
|
113
|
+
|
|
114
|
+
| Exception | When |
|
|
115
|
+
|---|---|
|
|
116
|
+
| `AuthenticationError` | 401: no key, a revoked key |
|
|
117
|
+
| `PlanLimitError` | 403: not in your plan |
|
|
118
|
+
| `NotFoundError` | 404: no such validation, or it expired (24 hours) |
|
|
119
|
+
| `NotFinishedError` | 409: the report of a validation still running |
|
|
120
|
+
| `DocumentTooLargeError` | 413: over your plan's size limit |
|
|
121
|
+
| `InvalidRequestError` | 422: unknown schema, a bad URL, … |
|
|
122
|
+
| `QuotaExceededError` | 429: this month's validations are used up |
|
|
123
|
+
| `RateLimitedError` | 429: still limited after the retries; `retry_after` seconds |
|
|
124
|
+
| `ServerError` | 5xx |
|
|
125
|
+
| `TransportError` | The request could not be sent or its answer read |
|
|
126
|
+
| `ValidationTimeoutError` | Still running after `timeout=` (also a `TimeoutError`) |
|
|
127
|
+
|
|
128
|
+
## Webhooks
|
|
129
|
+
|
|
130
|
+
On Pro, xmlvalid can call your endpoint when a validation finishes or a URL monitor changes
|
|
131
|
+
state. Check the signature with the endpoint's secret and the raw body:
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from xmlvalid import Event, webhooks
|
|
135
|
+
|
|
136
|
+
event = webhooks.verify(
|
|
137
|
+
request.body, # the raw bytes, as received
|
|
138
|
+
request.headers.get("Xmlvalid-Signature"),
|
|
139
|
+
os.environ["XMLVALID_WEBHOOK_SECRET"],
|
|
140
|
+
) # raises SignatureVerificationError
|
|
141
|
+
|
|
142
|
+
if event.type == Event.VALIDATION_COMPLETED:
|
|
143
|
+
validation = event.validation
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
A retried delivery has the same `event.id`. The other events are `monitor.failed`,
|
|
147
|
+
`monitor.recovered` (`event.data["monitor"]`, `event.data["check"]`) and `ping`.
|
|
148
|
+
|
|
149
|
+
## Options
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
Client(
|
|
153
|
+
api_key="xv_…", # default: XMLVALID_API_KEY
|
|
154
|
+
base_url="https://xmlvalid.com/api/v1",
|
|
155
|
+
timeout=900, # seconds validate() waits in all
|
|
156
|
+
wait=10, # seconds the API holds a new request (0-60)
|
|
157
|
+
max_retries=3, # retries of a 429 rate_limited
|
|
158
|
+
http_client=httpx.Client(...), # proxies, certificates, a mock transport in tests
|
|
159
|
+
)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Use it as a context manager, or call `close()`, to close the connection pool.
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
uv sync
|
|
168
|
+
uv run pytest
|
|
169
|
+
uv run mypy
|
|
170
|
+
uv run ruff check && uv run ruff format --check
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## License
|
|
174
|
+
|
|
175
|
+
MIT
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "xmlvalid"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Python client for the xmlvalid API: validate XML and e-invoices (Peppol, XRechnung, Factur-X, UBL, CII) against XSD, DTD, RelaxNG and Schematron business rules"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
authors = [{ name = "xmlvalid", email = "support@xmlvalid.com" }]
|
|
14
|
+
keywords = ["xml", "validation", "xsd", "schematron", "e-invoice", "peppol", "xrechnung", "factur-x", "ubl", "en16931"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 5 - Production/Stable",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
21
|
+
"Topic :: Text Processing :: Markup :: XML",
|
|
22
|
+
"Typing :: Typed",
|
|
23
|
+
]
|
|
24
|
+
dependencies = ["httpx>=0.27,<1"]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://xmlvalid.com"
|
|
28
|
+
Documentation = "https://xmlvalid.com/docs/api"
|
|
29
|
+
Source = "https://github.com/xmlvalid/xmlvalid-python"
|
|
30
|
+
Issues = "https://github.com/xmlvalid/xmlvalid-python/issues"
|
|
31
|
+
Changelog = "https://github.com/xmlvalid/xmlvalid-python/blob/main/CHANGELOG.md"
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = ["pytest>=8", "mypy>=1.13", "ruff>=0.8"]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.version]
|
|
37
|
+
path = "src/xmlvalid/_version.py"
|
|
38
|
+
|
|
39
|
+
[tool.hatch.build.targets.sdist]
|
|
40
|
+
include = ["src", "tests", "README.md", "CHANGELOG.md", "LICENSE"]
|
|
41
|
+
|
|
42
|
+
[tool.pytest.ini_options]
|
|
43
|
+
testpaths = ["tests"]
|
|
44
|
+
filterwarnings = ["error"]
|
|
45
|
+
|
|
46
|
+
[tool.mypy]
|
|
47
|
+
strict = true
|
|
48
|
+
files = ["src", "tests"]
|
|
49
|
+
|
|
50
|
+
[tool.ruff]
|
|
51
|
+
line-length = 120
|
|
52
|
+
target-version = "py310"
|
|
53
|
+
|
|
54
|
+
[tool.ruff.lint]
|
|
55
|
+
select = ["E", "F", "W", "I", "UP", "B", "SIM", "RUF"]
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Python client for the xmlvalid API: https://xmlvalid.com/docs/api"""
|
|
2
|
+
|
|
3
|
+
from . import webhooks
|
|
4
|
+
from ._client import DEFAULT_BASE_URL, AsyncClient, Client, DocumentInput, Rules
|
|
5
|
+
from ._version import __version__
|
|
6
|
+
from .errors import (
|
|
7
|
+
ApiError,
|
|
8
|
+
AuthenticationError,
|
|
9
|
+
DocumentTooLargeError,
|
|
10
|
+
InvalidRequestError,
|
|
11
|
+
NotFinishedError,
|
|
12
|
+
NotFoundError,
|
|
13
|
+
PlanLimitError,
|
|
14
|
+
QuotaExceededError,
|
|
15
|
+
RateLimitedError,
|
|
16
|
+
ServerError,
|
|
17
|
+
SignatureVerificationError,
|
|
18
|
+
TransportError,
|
|
19
|
+
ValidationTimeoutError,
|
|
20
|
+
XmlvalidError,
|
|
21
|
+
)
|
|
22
|
+
from .models import ArchiveItem, Diagnostic, Event, ReportLink, Result, Schema, Usage, Validation
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"DEFAULT_BASE_URL",
|
|
26
|
+
"ApiError",
|
|
27
|
+
"ArchiveItem",
|
|
28
|
+
"AsyncClient",
|
|
29
|
+
"AuthenticationError",
|
|
30
|
+
"Client",
|
|
31
|
+
"Diagnostic",
|
|
32
|
+
"DocumentInput",
|
|
33
|
+
"DocumentTooLargeError",
|
|
34
|
+
"Event",
|
|
35
|
+
"InvalidRequestError",
|
|
36
|
+
"NotFinishedError",
|
|
37
|
+
"NotFoundError",
|
|
38
|
+
"PlanLimitError",
|
|
39
|
+
"QuotaExceededError",
|
|
40
|
+
"RateLimitedError",
|
|
41
|
+
"ReportLink",
|
|
42
|
+
"Result",
|
|
43
|
+
"Rules",
|
|
44
|
+
"Schema",
|
|
45
|
+
"ServerError",
|
|
46
|
+
"SignatureVerificationError",
|
|
47
|
+
"TransportError",
|
|
48
|
+
"Usage",
|
|
49
|
+
"Validation",
|
|
50
|
+
"ValidationTimeoutError",
|
|
51
|
+
"XmlvalidError",
|
|
52
|
+
"__version__",
|
|
53
|
+
"webhooks",
|
|
54
|
+
]
|