cbor-model 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.
- cbor_model-0.1.0/PKG-INFO +146 -0
- cbor_model-0.1.0/README.md +121 -0
- cbor_model-0.1.0/pyproject.toml +62 -0
- cbor_model-0.1.0/src/cbor_model/__about__.py +5 -0
- cbor_model-0.1.0/src/cbor_model/__init__.py +16 -0
- cbor_model-0.1.0/src/cbor_model/_config.py +46 -0
- cbor_model-0.1.0/src/cbor_model/_field.py +91 -0
- cbor_model-0.1.0/src/cbor_model/_model.py +479 -0
- cbor_model-0.1.0/src/cbor_model/cddl/__init__.py +3 -0
- cbor_model-0.1.0/src/cbor_model/cddl/_cddl.py +189 -0
- cbor_model-0.1.0/src/cbor_model/cddl/_field_processor.py +48 -0
- cbor_model-0.1.0/src/cbor_model/cddl/_type_converter.py +201 -0
- cbor_model-0.1.0/src/cbor_model/cddl/_util.py +36 -0
- cbor_model-0.1.0/src/cbor_model/py.typed +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cbor-model
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CBOR Model: Add CBOR and CDDL support to Pydantic models
|
|
5
|
+
Keywords: serialization,cbor,cddl
|
|
6
|
+
Author: William Häggqvist
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Dist: cbor2>=5.8.0
|
|
20
|
+
Requires-Dist: pydantic>=2.12.5
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Project-URL: repository, https://github.com/haggqvist/cbor-model
|
|
23
|
+
Project-URL: issues, https://github.com/haggqvist/cbor-model/issues
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# CBOR Model
|
|
27
|
+
|
|
28
|
+
`cbor-model` adds [CBOR] serialization and [CDDL] schema generation to [Pydantic]
|
|
29
|
+
models.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install cbor-model
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
or with [uv]:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
uv add cbor-model
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
### Map encoding
|
|
46
|
+
|
|
47
|
+
Fields are encoded as a CBOR map keyed by the integer or string supplied to
|
|
48
|
+
`CBORField(key=...)`.
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from typing import Annotated
|
|
52
|
+
from cbor_model import CBORModel, CBORField
|
|
53
|
+
|
|
54
|
+
class Sensor(CBORModel):
|
|
55
|
+
name: Annotated[str, CBORField(key=0)]
|
|
56
|
+
value: Annotated[float, CBORField(key=1)]
|
|
57
|
+
|
|
58
|
+
sensor = Sensor(name="temp", value=21.5)
|
|
59
|
+
data = sensor.model_dump_cbor() # a2006474656d7001fb4035800000000000
|
|
60
|
+
assert Sensor.model_validate_cbor(data) == sensor
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Array encoding
|
|
64
|
+
|
|
65
|
+
Switch to array encoding by setting `CBORConfig(encoding="array")` and using
|
|
66
|
+
`CBORField(index=...)` — fields are serialized in index order.
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from typing import Annotated
|
|
70
|
+
from cbor_model import CBORModel, CBORField, CBORConfig
|
|
71
|
+
|
|
72
|
+
class Point(CBORModel):
|
|
73
|
+
cbor_config = CBORConfig(encoding="array")
|
|
74
|
+
|
|
75
|
+
x: Annotated[int, CBORField(index=0)]
|
|
76
|
+
y: Annotated[int, CBORField(index=1)]
|
|
77
|
+
|
|
78
|
+
pt = Point(x=4, y=2)
|
|
79
|
+
data = pt.model_dump_cbor() # 820402
|
|
80
|
+
assert Point.model_validate_cbor(data) == pt
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### CBOR tags
|
|
84
|
+
|
|
85
|
+
Wrap a field's value in a CBOR tag using `CBORField(tag=...)`, or tag the entire
|
|
86
|
+
model with `CBORConfig(tag=...)`.
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from typing import Annotated
|
|
90
|
+
from cbor_model import CBORModel, CBORField, CBORConfig
|
|
91
|
+
|
|
92
|
+
class Reading(CBORModel):
|
|
93
|
+
cbor_config = CBORConfig(tag=40001)
|
|
94
|
+
|
|
95
|
+
sensor_id: Annotated[int, CBORField(key=0)]
|
|
96
|
+
raw: Annotated[bytes, CBORField(key=1, tag=40002)]
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Serialization context
|
|
100
|
+
|
|
101
|
+
Pass a `CBORSerializationContext` to control `None` and empty-collection exclusion:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from cbor_model import CBORSerializationContext
|
|
105
|
+
|
|
106
|
+
ctx = CBORSerializationContext(exclude_none=False, exclude_empty=False)
|
|
107
|
+
data = sensor.model_dump_cbor(context=ctx)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Custom encoders
|
|
111
|
+
|
|
112
|
+
Register encoders for types not natively supported by [cbor2]:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import decimal
|
|
116
|
+
from cbor_model import CBORConfig
|
|
117
|
+
|
|
118
|
+
class MyModel(CBORModel):
|
|
119
|
+
cbor_config = CBORConfig(
|
|
120
|
+
encoders={decimal.Decimal: lambda d: str(d)}
|
|
121
|
+
)
|
|
122
|
+
amount: Annotated[decimal.Decimal, CBORField(key=0)]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### CDDL generation
|
|
126
|
+
|
|
127
|
+
Generate a [CDDL] schema from one or more models:
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from cbor_model.cddl import CDDLGenerator
|
|
131
|
+
|
|
132
|
+
print(CDDLGenerator().generate(Sensor))
|
|
133
|
+
# Sensor = {
|
|
134
|
+
# ? 0: text, ; name
|
|
135
|
+
# ? 1: float, ; value
|
|
136
|
+
# }
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
[CBOR]: https://cbor.io/
|
|
140
|
+
[CDDL]: https://www.rfc-editor.org/rfc/rfc8610
|
|
141
|
+
[Pydantic]: https://github.com/pydantic/pydantic
|
|
142
|
+
[cbor2]: https://github.com/agronholm/cbor2
|
|
143
|
+
[uv]: https://docs.astral.sh/uv/
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
[pydantic]: https://github.com/pydantic/pydantic
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# CBOR Model
|
|
2
|
+
|
|
3
|
+
`cbor-model` adds [CBOR] serialization and [CDDL] schema generation to [Pydantic]
|
|
4
|
+
models.
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pip install cbor-model
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
or with [uv]:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv add cbor-model
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
### Map encoding
|
|
21
|
+
|
|
22
|
+
Fields are encoded as a CBOR map keyed by the integer or string supplied to
|
|
23
|
+
`CBORField(key=...)`.
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from typing import Annotated
|
|
27
|
+
from cbor_model import CBORModel, CBORField
|
|
28
|
+
|
|
29
|
+
class Sensor(CBORModel):
|
|
30
|
+
name: Annotated[str, CBORField(key=0)]
|
|
31
|
+
value: Annotated[float, CBORField(key=1)]
|
|
32
|
+
|
|
33
|
+
sensor = Sensor(name="temp", value=21.5)
|
|
34
|
+
data = sensor.model_dump_cbor() # a2006474656d7001fb4035800000000000
|
|
35
|
+
assert Sensor.model_validate_cbor(data) == sensor
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Array encoding
|
|
39
|
+
|
|
40
|
+
Switch to array encoding by setting `CBORConfig(encoding="array")` and using
|
|
41
|
+
`CBORField(index=...)` — fields are serialized in index order.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from typing import Annotated
|
|
45
|
+
from cbor_model import CBORModel, CBORField, CBORConfig
|
|
46
|
+
|
|
47
|
+
class Point(CBORModel):
|
|
48
|
+
cbor_config = CBORConfig(encoding="array")
|
|
49
|
+
|
|
50
|
+
x: Annotated[int, CBORField(index=0)]
|
|
51
|
+
y: Annotated[int, CBORField(index=1)]
|
|
52
|
+
|
|
53
|
+
pt = Point(x=4, y=2)
|
|
54
|
+
data = pt.model_dump_cbor() # 820402
|
|
55
|
+
assert Point.model_validate_cbor(data) == pt
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### CBOR tags
|
|
59
|
+
|
|
60
|
+
Wrap a field's value in a CBOR tag using `CBORField(tag=...)`, or tag the entire
|
|
61
|
+
model with `CBORConfig(tag=...)`.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from typing import Annotated
|
|
65
|
+
from cbor_model import CBORModel, CBORField, CBORConfig
|
|
66
|
+
|
|
67
|
+
class Reading(CBORModel):
|
|
68
|
+
cbor_config = CBORConfig(tag=40001)
|
|
69
|
+
|
|
70
|
+
sensor_id: Annotated[int, CBORField(key=0)]
|
|
71
|
+
raw: Annotated[bytes, CBORField(key=1, tag=40002)]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Serialization context
|
|
75
|
+
|
|
76
|
+
Pass a `CBORSerializationContext` to control `None` and empty-collection exclusion:
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
from cbor_model import CBORSerializationContext
|
|
80
|
+
|
|
81
|
+
ctx = CBORSerializationContext(exclude_none=False, exclude_empty=False)
|
|
82
|
+
data = sensor.model_dump_cbor(context=ctx)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Custom encoders
|
|
86
|
+
|
|
87
|
+
Register encoders for types not natively supported by [cbor2]:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import decimal
|
|
91
|
+
from cbor_model import CBORConfig
|
|
92
|
+
|
|
93
|
+
class MyModel(CBORModel):
|
|
94
|
+
cbor_config = CBORConfig(
|
|
95
|
+
encoders={decimal.Decimal: lambda d: str(d)}
|
|
96
|
+
)
|
|
97
|
+
amount: Annotated[decimal.Decimal, CBORField(key=0)]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### CDDL generation
|
|
101
|
+
|
|
102
|
+
Generate a [CDDL] schema from one or more models:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from cbor_model.cddl import CDDLGenerator
|
|
106
|
+
|
|
107
|
+
print(CDDLGenerator().generate(Sensor))
|
|
108
|
+
# Sensor = {
|
|
109
|
+
# ? 0: text, ; name
|
|
110
|
+
# ? 1: float, ; value
|
|
111
|
+
# }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
[CBOR]: https://cbor.io/
|
|
115
|
+
[CDDL]: https://www.rfc-editor.org/rfc/rfc8610
|
|
116
|
+
[Pydantic]: https://github.com/pydantic/pydantic
|
|
117
|
+
[cbor2]: https://github.com/agronholm/cbor2
|
|
118
|
+
[uv]: https://docs.astral.sh/uv/
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
[pydantic]: https://github.com/pydantic/pydantic
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "cbor-model"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "CBOR Model: Add CBOR and CDDL support to Pydantic models"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "William Häggqvist" }
|
|
8
|
+
]
|
|
9
|
+
requires-python = ">=3.12"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"cbor2>=5.8.0",
|
|
12
|
+
"pydantic>=2.12.5",
|
|
13
|
+
]
|
|
14
|
+
license = "MIT"
|
|
15
|
+
keywords = [
|
|
16
|
+
"serialization",
|
|
17
|
+
"cbor",
|
|
18
|
+
"cddl"
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
"Programming Language :: Python",
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Programming Language :: Python :: 3.13",
|
|
30
|
+
"Programming Language :: Python :: 3.14",
|
|
31
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
32
|
+
"Typing :: Typed"
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
repository = "https://github.com/haggqvist/cbor-model"
|
|
37
|
+
issues = "https://github.com/haggqvist/cbor-model/issues"
|
|
38
|
+
|
|
39
|
+
[build-system]
|
|
40
|
+
requires = ["uv_build>=0.10,<0.11.0"]
|
|
41
|
+
build-backend = "uv_build"
|
|
42
|
+
|
|
43
|
+
[tool.ruff]
|
|
44
|
+
line-length = 88
|
|
45
|
+
fix = true
|
|
46
|
+
target-version = "py312"
|
|
47
|
+
|
|
48
|
+
[tool.ruff.lint]
|
|
49
|
+
ignore = ["D104"]
|
|
50
|
+
extend-select = ["I"]
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint.per-file-ignores]
|
|
53
|
+
"**/tests/*" = ["S101", "D"]
|
|
54
|
+
|
|
55
|
+
[tool.pytest.ini_options]
|
|
56
|
+
pythonpath = ["."]
|
|
57
|
+
|
|
58
|
+
[dependency-groups]
|
|
59
|
+
dev = [
|
|
60
|
+
"pre-commit>=4.5.1",
|
|
61
|
+
"pytest>=9.0.2",
|
|
62
|
+
]
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from .__about__ import __application__, __author__, __version__
|
|
2
|
+
from ._config import CBORConfig
|
|
3
|
+
from ._field import CBORField
|
|
4
|
+
from ._model import CBORModel, CBORSerializationContext
|
|
5
|
+
from .cddl import CDDLGenerator
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"CBORConfig",
|
|
9
|
+
"CBORField",
|
|
10
|
+
"CBORModel",
|
|
11
|
+
"CBORSerializationContext",
|
|
12
|
+
"CDDLGenerator",
|
|
13
|
+
"__application__",
|
|
14
|
+
"__author__",
|
|
15
|
+
"__version__",
|
|
16
|
+
]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Any, Literal
|
|
4
|
+
|
|
5
|
+
type CBOREncoders = dict[type, Callable[[Any], Any]]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True, slots=True)
|
|
9
|
+
class CBORConfig:
|
|
10
|
+
"""Configuration options for :class:`~cbor_model.CBORModel` instances.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
encoding: Whether to encode the model as a CBOR map (keyed by
|
|
14
|
+
`CBORField(key=...)`) or as a CBOR array (ordered by
|
|
15
|
+
`CBORField(index=...)`). Defaults to `"map"`.
|
|
16
|
+
tag: Wrap the encoded model in a CBOR tag with this tag number.
|
|
17
|
+
`None` disables tagging (default).
|
|
18
|
+
canonical: Use canonical CBOR encoding (deterministic key ordering
|
|
19
|
+
and minimal integer encoding). Defaults to `False`.
|
|
20
|
+
encoders: Custom encoders for types not natively supported by
|
|
21
|
+
cbor2. Keys are Python types; values are callables that
|
|
22
|
+
convert an instance of that type to a cbor2-encodable value
|
|
23
|
+
(e.g. `str`, `int`, `list`, `dict`).
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
encoding: Literal["map", "array"] = "map"
|
|
28
|
+
"""Whether to encode the model as a CBOR map (key-value pairs) or array
|
|
29
|
+
(positional). Defaults to "map"."""
|
|
30
|
+
|
|
31
|
+
tag: int | None = None
|
|
32
|
+
"""Wrap the CBORModel in a CBOR Tag on serialization."""
|
|
33
|
+
|
|
34
|
+
canonical: bool = False
|
|
35
|
+
"""Whether to use canonical CBOR encoding. Defaults to `False`."""
|
|
36
|
+
|
|
37
|
+
encoders: CBOREncoders = field(default_factory=dict)
|
|
38
|
+
"""Custom encoders for types that are not natively supported by cbor2.
|
|
39
|
+
The keys should be types, and the values should be callables that take an
|
|
40
|
+
instance of the type and return a value that can be encoded by cbor2 (e.g.
|
|
41
|
+
a string, int, list, dict, etc.)."""
|
|
42
|
+
|
|
43
|
+
def __post_init__(self) -> None:
|
|
44
|
+
if self.tag is not None and self.tag < 0:
|
|
45
|
+
err = f"CBOR tag {self.tag} is invalid. Tags must be non-negative integers."
|
|
46
|
+
raise ValueError(err)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
|
|
9
|
+
CBOR2_RESERVED_TAGS = frozenset(
|
|
10
|
+
{0, 1, 2, 3, 4, 5, 25, 28, 29, 30, 35, 36, 37, 100, 256, 258, 260, 261},
|
|
11
|
+
)
|
|
12
|
+
"""CBOR tags reserved by cbor2 library with semantic decoders."""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True, slots=True)
|
|
16
|
+
class CBORField:
|
|
17
|
+
"""Marks a :class:`~pydantic.BaseModel` field for CBOR serialization.
|
|
18
|
+
|
|
19
|
+
Exactly one of `key` or `index` must be provided. Attach a `CBORField` to a
|
|
20
|
+
field via :data:`typing.Annotated`:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from typing import Annotated
|
|
24
|
+
from cbor_model import CBORModel, CBORField
|
|
25
|
+
|
|
26
|
+
class MyModel(CBORModel):
|
|
27
|
+
name: Annotated[str, CBORField(key=0)]
|
|
28
|
+
value: Annotated[int, CBORField(key=1)]
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
key: Map key used when the parent model uses `encoding="map"`. May be
|
|
33
|
+
an integer or a string.
|
|
34
|
+
index: Zero-based position used when the parent model uses
|
|
35
|
+
`encoding="array"`. Indices must be contiguous starting from 0,
|
|
36
|
+
with optional fields at the tail.
|
|
37
|
+
tag: CBOR tag number to wrap this field's value in on serialization.
|
|
38
|
+
Use values above 1000 to avoid conflicts with standard tags. See
|
|
39
|
+
`CBOR2_RESERVED_TAGS` for tags reserved by cbor2.
|
|
40
|
+
override_type: Override the CDDL type name emitted by
|
|
41
|
+
:class:`CDDLGenerator` for this field.
|
|
42
|
+
override_name: Override the CDDL field name emitted by
|
|
43
|
+
:class:`CDDLGenerator` for this field.
|
|
44
|
+
optional: Mark the field as optional in CDDL output regardless of
|
|
45
|
+
its Python type annotation.
|
|
46
|
+
exclude_if: A callable that receives the field value and returns
|
|
47
|
+
`True` if the field should be omitted from the serialized output.
|
|
48
|
+
Useful for custom exclusion logic beyond `None` or empty values.
|
|
49
|
+
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
key: int | str | None = None
|
|
53
|
+
index: int | None = None
|
|
54
|
+
tag: int | None = None
|
|
55
|
+
"""Custom CBOR tag number. Use values >1000 to avoid conflicts with
|
|
56
|
+
standard tags.
|
|
57
|
+
|
|
58
|
+
See `CBOR2_RESERVED_TAGS` for tags reserved by cbor2 library.
|
|
59
|
+
"""
|
|
60
|
+
override_type: str | None = None
|
|
61
|
+
override_name: str | None = None
|
|
62
|
+
optional: bool = False
|
|
63
|
+
exclude_if: Callable[[Any], bool] | None = None
|
|
64
|
+
"""A Callable that takes the field value and returns `True` if the field should be excluded from serialization. This can be used to implement custom exclusion logic beyond just `None` or empty values.""" # noqa: E501
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def identifier(self) -> int | str:
|
|
68
|
+
"""The CBOR map key or array index used to identify this field.
|
|
69
|
+
|
|
70
|
+
Returns `key` when the field belongs to a map-encoded model, or
|
|
71
|
+
`index` when it belongs to an array-encoded model.
|
|
72
|
+
"""
|
|
73
|
+
return self.key if self.key is not None else cast("int", self.index)
|
|
74
|
+
|
|
75
|
+
def __post_init__(self) -> None:
|
|
76
|
+
if self.key is not None and self.index is not None:
|
|
77
|
+
err = "Cannot specify both key and index for CBORField"
|
|
78
|
+
raise ValueError(err)
|
|
79
|
+
if self.key is None and self.index is None:
|
|
80
|
+
err = "Must specify either key or index for CBORField"
|
|
81
|
+
raise ValueError(err)
|
|
82
|
+
if self.tag is not None:
|
|
83
|
+
if self.tag < 0:
|
|
84
|
+
err = f"CBOR tag {self.tag} is invalid. Tags must be non-negative integers."
|
|
85
|
+
raise ValueError(err)
|
|
86
|
+
if self.tag in CBOR2_RESERVED_TAGS:
|
|
87
|
+
err = (
|
|
88
|
+
f"CBOR tag {self.tag} conflicts with cbor2 reserved tags. "
|
|
89
|
+
f"Use tag values > 1000 to avoid conflicts with standard CBOR tags."
|
|
90
|
+
)
|
|
91
|
+
raise ValueError(err)
|