pydantic-marshmallow 1.0.0__py3-none-any.whl
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.
- pydantic_marshmallow/__init__.py +79 -0
- pydantic_marshmallow/bridge.py +1187 -0
- pydantic_marshmallow/errors.py +154 -0
- pydantic_marshmallow/field_conversion.py +137 -0
- pydantic_marshmallow/py.typed +2 -0
- pydantic_marshmallow/type_mapping.py +138 -0
- pydantic_marshmallow/validators.py +207 -0
- pydantic_marshmallow-1.0.0.dist-info/METADATA +367 -0
- pydantic_marshmallow-1.0.0.dist-info/RECORD +12 -0
- pydantic_marshmallow-1.0.0.dist-info/WHEEL +5 -0
- pydantic_marshmallow-1.0.0.dist-info/licenses/LICENSE +21 -0
- pydantic_marshmallow-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pydantic-marshmallow
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Bring Pydantic's power to Marshmallow: type annotations, validators, and automatic schema generation
|
|
5
|
+
Author-email: Your Name <your.email@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/mockodin/pydantic-marshmallow
|
|
8
|
+
Project-URL: Documentation, https://mockodin.github.io/pydantic-marshmallow
|
|
9
|
+
Project-URL: Repository, https://github.com/mockodin/pydantic-marshmallow
|
|
10
|
+
Project-URL: Issues, https://github.com/mockodin/pydantic-marshmallow/issues
|
|
11
|
+
Keywords: pydantic,marshmallow,validation,serialization,type-hints
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
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 :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Requires-Dist: marshmallow>=3.18.0
|
|
28
|
+
Requires-Dist: pydantic>=2.0.0
|
|
29
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
30
|
+
Requires-Dist: orjson>=3.9.0
|
|
31
|
+
Provides-Extra: dev
|
|
32
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
34
|
+
Requires-Dist: email-validator>=2.1.0; extra == "dev"
|
|
35
|
+
Requires-Dist: mypy>=1.10.0; extra == "dev"
|
|
36
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
37
|
+
Requires-Dist: flake8>=7.1.0; extra == "dev"
|
|
38
|
+
Requires-Dist: flake8-pyproject>=1.2.4; extra == "dev"
|
|
39
|
+
Requires-Dist: sqlalchemy>=2.0.30; extra == "dev"
|
|
40
|
+
Requires-Dist: marshmallow-sqlalchemy>=1.1.0; extra == "dev"
|
|
41
|
+
Requires-Dist: flask>=3.0.0; extra == "dev"
|
|
42
|
+
Requires-Dist: flask-marshmallow>=1.2.0; extra == "dev"
|
|
43
|
+
Requires-Dist: webargs>=8.5.0; extra == "dev"
|
|
44
|
+
Requires-Dist: apispec>=6.5.0; extra == "dev"
|
|
45
|
+
Requires-Dist: pyyaml>=6.0.1; extra == "dev"
|
|
46
|
+
Requires-Dist: flask-rebar>=3.0.0; extra == "dev"
|
|
47
|
+
Requires-Dist: flask-smorest>=0.44.0; extra == "dev"
|
|
48
|
+
Requires-Dist: marshmallow-dataclass>=8.7.0; extra == "dev"
|
|
49
|
+
Requires-Dist: marshmallow-oneofschema>=3.1.0; extra == "dev"
|
|
50
|
+
Requires-Dist: connexion[flask,swagger-ui,uvicorn]>=3.1.0; extra == "dev"
|
|
51
|
+
Provides-Extra: docs
|
|
52
|
+
Requires-Dist: mkdocs>=1.6.0; extra == "docs"
|
|
53
|
+
Requires-Dist: mkdocs-material>=9.5.0; extra == "docs"
|
|
54
|
+
Requires-Dist: mkdocstrings[python]>=0.26.0; extra == "docs"
|
|
55
|
+
Provides-Extra: all
|
|
56
|
+
Requires-Dist: pydantic-marshmallow[dev,docs]; extra == "all"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
# pydantic-marshmallow
|
|
60
|
+
|
|
61
|
+
[](https://github.com/mockodin/pydantic-marshmallow/actions/workflows/ci.yml)
|
|
62
|
+
[](https://badge.fury.io/py/pydantic-marshmallow)
|
|
63
|
+
[](https://www.python.org/downloads/)
|
|
64
|
+
[](https://opensource.org/licenses/MIT)
|
|
65
|
+
|
|
66
|
+
Bridge Pydantic's power with Marshmallow's ecosystem. Use Pydantic models for validation with full Marshmallow compatibility.
|
|
67
|
+
|
|
68
|
+
📖 **[Documentation](https://mockodin.github.io/pydantic-marshmallow)** | 🐙 **[GitHub](https://github.com/mockodin/pydantic-marshmallow)**
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
- **Pydantic Validation**: Leverage Pydantic's Rust-powered validation engine
|
|
73
|
+
- **Marshmallow Compatibility**: Works with Flask-Marshmallow, webargs, apispec, SQLAlchemy, and more
|
|
74
|
+
- **Zero Drift**: Single source of truth - Pydantic model defines the schema
|
|
75
|
+
- **Full Hook Support**: `@pre_load`, `@post_load`, `@pre_dump`, `@post_dump`
|
|
76
|
+
- **Validators**: `@validates("field")` and `@validates_schema` decorators
|
|
77
|
+
- **Partial Loading**: `partial=True` or `partial=('field1', 'field2')`
|
|
78
|
+
- **Unknown Fields**: `unknown=RAISE/EXCLUDE/INCLUDE`
|
|
79
|
+
- **Computed Fields**: Pydantic `@computed_field` support in serialization
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
pip install pydantic-marshmallow
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Quick Start
|
|
88
|
+
|
|
89
|
+
### Basic Usage
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from pydantic import BaseModel, EmailStr, Field
|
|
93
|
+
from pydantic_marshmallow import PydanticSchema
|
|
94
|
+
|
|
95
|
+
class User(BaseModel):
|
|
96
|
+
name: str = Field(min_length=1)
|
|
97
|
+
email: EmailStr
|
|
98
|
+
age: int = Field(ge=0)
|
|
99
|
+
|
|
100
|
+
class UserSchema(PydanticSchema[User]):
|
|
101
|
+
class Meta:
|
|
102
|
+
model = User
|
|
103
|
+
|
|
104
|
+
# Use like any Marshmallow schema
|
|
105
|
+
schema = UserSchema()
|
|
106
|
+
user = schema.load({"name": "Alice", "email": "alice@example.com", "age": 30})
|
|
107
|
+
print(user.name) # "Alice" - it's a Pydantic User instance!
|
|
108
|
+
|
|
109
|
+
# Serialize back
|
|
110
|
+
data = schema.dump(user)
|
|
111
|
+
# {"name": "Alice", "email": "alice@example.com", "age": 30}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Using the Decorator
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from pydantic_marshmallow import pydantic_schema
|
|
118
|
+
|
|
119
|
+
@pydantic_schema
|
|
120
|
+
class User(BaseModel):
|
|
121
|
+
name: str
|
|
122
|
+
email: EmailStr
|
|
123
|
+
|
|
124
|
+
# .Schema attribute is automatically added
|
|
125
|
+
schema = User.Schema()
|
|
126
|
+
user = schema.load({"name": "Alice", "email": "alice@example.com"})
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Factory Function
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from pydantic_marshmallow import schema_for
|
|
133
|
+
|
|
134
|
+
UserSchema = schema_for(User)
|
|
135
|
+
schema = UserSchema()
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Marshmallow Hooks
|
|
139
|
+
|
|
140
|
+
All standard Marshmallow hooks work:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from marshmallow import pre_load, post_load, validates
|
|
144
|
+
|
|
145
|
+
class UserSchema(PydanticSchema[User]):
|
|
146
|
+
class Meta:
|
|
147
|
+
model = User
|
|
148
|
+
|
|
149
|
+
@pre_load
|
|
150
|
+
def normalize_email(self, data, **kwargs):
|
|
151
|
+
if "email" in data:
|
|
152
|
+
data["email"] = data["email"].lower().strip()
|
|
153
|
+
return data
|
|
154
|
+
|
|
155
|
+
@post_load
|
|
156
|
+
def log_user(self, user, **kwargs):
|
|
157
|
+
print(f"Loaded user: {user.name}")
|
|
158
|
+
return user
|
|
159
|
+
|
|
160
|
+
@validates("name")
|
|
161
|
+
def validate_name(self, value):
|
|
162
|
+
if value.lower() == "admin":
|
|
163
|
+
raise ValidationError("Cannot use 'admin' as name")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Partial Loading
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
# Allow all missing required fields
|
|
170
|
+
user = schema.load({"name": "Alice"}, partial=True)
|
|
171
|
+
|
|
172
|
+
# Allow specific missing fields
|
|
173
|
+
user = schema.load({"name": "Alice"}, partial=("email", "age"))
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Unknown Field Handling
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from marshmallow import EXCLUDE, INCLUDE, RAISE
|
|
180
|
+
|
|
181
|
+
# Reject unknown fields (default)
|
|
182
|
+
schema = UserSchema(unknown=RAISE)
|
|
183
|
+
|
|
184
|
+
# Ignore unknown fields
|
|
185
|
+
schema = UserSchema(unknown=EXCLUDE)
|
|
186
|
+
|
|
187
|
+
# Include unknown fields in result
|
|
188
|
+
schema = UserSchema(unknown=INCLUDE)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Field Filtering
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
# Only include specific fields
|
|
195
|
+
schema = UserSchema(only=("name", "email"))
|
|
196
|
+
|
|
197
|
+
# Exclude specific fields
|
|
198
|
+
schema = UserSchema(exclude=("age",))
|
|
199
|
+
|
|
200
|
+
# Load-only fields (not in dump output)
|
|
201
|
+
schema = UserSchema(load_only=("password",))
|
|
202
|
+
|
|
203
|
+
# Dump-only fields (not in load input)
|
|
204
|
+
schema = UserSchema(dump_only=("created_at",))
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Computed Fields
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from pydantic import computed_field
|
|
211
|
+
|
|
212
|
+
class User(BaseModel):
|
|
213
|
+
first: str
|
|
214
|
+
last: str
|
|
215
|
+
|
|
216
|
+
@computed_field
|
|
217
|
+
@property
|
|
218
|
+
def full_name(self) -> str:
|
|
219
|
+
return f"{self.first} {self.last}"
|
|
220
|
+
|
|
221
|
+
schema = schema_for(User)()
|
|
222
|
+
user = User(first="Alice", last="Smith")
|
|
223
|
+
data = schema.dump(user)
|
|
224
|
+
# {"first": "Alice", "last": "Smith", "full_name": "Alice Smith"}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Dump Options
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
# Exclude None values
|
|
231
|
+
schema.dump(user, exclude_none=True)
|
|
232
|
+
|
|
233
|
+
# Exclude unset fields
|
|
234
|
+
schema.dump(user, exclude_unset=True)
|
|
235
|
+
|
|
236
|
+
# Exclude fields with default values
|
|
237
|
+
schema.dump(user, exclude_defaults=True)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Flask-Marshmallow Integration
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
from flask import Flask
|
|
244
|
+
from flask_marshmallow import Marshmallow
|
|
245
|
+
from pydantic_marshmallow import schema_for
|
|
246
|
+
|
|
247
|
+
app = Flask(__name__)
|
|
248
|
+
ma = Marshmallow(app)
|
|
249
|
+
|
|
250
|
+
UserSchema = schema_for(User)
|
|
251
|
+
|
|
252
|
+
@app.route("/users", methods=["POST"])
|
|
253
|
+
def create_user():
|
|
254
|
+
schema = UserSchema()
|
|
255
|
+
user = schema.load(request.json)
|
|
256
|
+
# user is a Pydantic User instance
|
|
257
|
+
return schema.dump(user)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## webargs Integration
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
from webargs.flaskparser import use_args
|
|
264
|
+
from pydantic_marshmallow import schema_for
|
|
265
|
+
|
|
266
|
+
UserSchema = schema_for(User)
|
|
267
|
+
|
|
268
|
+
@app.route("/users", methods=["POST"])
|
|
269
|
+
@use_args(UserSchema(), location="json")
|
|
270
|
+
def create_user(user):
|
|
271
|
+
# user is a Pydantic User instance
|
|
272
|
+
return {"message": f"Created {user.name}"}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## apispec Integration
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
from apispec import APISpec
|
|
279
|
+
from apispec.ext.marshmallow import MarshmallowPlugin
|
|
280
|
+
|
|
281
|
+
spec = APISpec(
|
|
282
|
+
title="My API",
|
|
283
|
+
version="1.0.0",
|
|
284
|
+
openapi_version="3.0.0",
|
|
285
|
+
plugins=[MarshmallowPlugin()],
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
spec.components.schema("User", schema=UserSchema)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## HybridModel
|
|
292
|
+
|
|
293
|
+
For models that need both Pydantic and Marshmallow APIs:
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
from pydantic_marshmallow import HybridModel
|
|
297
|
+
|
|
298
|
+
class User(HybridModel):
|
|
299
|
+
name: str
|
|
300
|
+
email: EmailStr
|
|
301
|
+
|
|
302
|
+
# Use as Pydantic model
|
|
303
|
+
user = User(name="Alice", email="alice@example.com")
|
|
304
|
+
|
|
305
|
+
# Use Marshmallow-style loading
|
|
306
|
+
user = User.ma_load({"name": "Alice", "email": "alice@example.com"})
|
|
307
|
+
|
|
308
|
+
# Get the Marshmallow schema class
|
|
309
|
+
schema_class = User.marshmallow_schema()
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Error Handling
|
|
313
|
+
|
|
314
|
+
Validation errors are raised as `BridgeValidationError`, which extends Marshmallow's `ValidationError`:
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
from pydantic_marshmallow import BridgeValidationError
|
|
318
|
+
|
|
319
|
+
try:
|
|
320
|
+
user = schema.load({"name": "", "email": "invalid"})
|
|
321
|
+
except BridgeValidationError as e:
|
|
322
|
+
print(e.messages)
|
|
323
|
+
# {'name': ['String should have at least 1 character'],
|
|
324
|
+
# 'email': ['value is not a valid email address']}
|
|
325
|
+
print(e.valid_data)
|
|
326
|
+
# {} - fields that passed validation
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## API Reference
|
|
330
|
+
|
|
331
|
+
### PydanticSchema
|
|
332
|
+
|
|
333
|
+
A Marshmallow schema backed by a Pydantic model.
|
|
334
|
+
|
|
335
|
+
**Class Methods:**
|
|
336
|
+
- `from_model(model, **meta_options)` - Create a schema class from a Pydantic model
|
|
337
|
+
|
|
338
|
+
**Instance Methods:**
|
|
339
|
+
- `load(data, *, many, partial, unknown, return_instance)` - Deserialize data
|
|
340
|
+
- `dump(obj, *, many, exclude_none, exclude_unset, exclude_defaults)` - Serialize data
|
|
341
|
+
- `validate(data, *, many, partial)` - Validate without deserializing
|
|
342
|
+
|
|
343
|
+
**Hooks:**
|
|
344
|
+
- `on_bind_field(field_name, field_obj)` - Called when a field is bound
|
|
345
|
+
- `handle_error(error, data, *, many)` - Custom error handling
|
|
346
|
+
|
|
347
|
+
### Factory Functions
|
|
348
|
+
|
|
349
|
+
- `schema_for(model, **meta_options)` - Create a schema class from a model
|
|
350
|
+
- `pydantic_schema` - Decorator that adds `.Schema` to a model
|
|
351
|
+
|
|
352
|
+
### HybridModel
|
|
353
|
+
|
|
354
|
+
A Pydantic model with built-in Marshmallow support.
|
|
355
|
+
|
|
356
|
+
**Class Methods:**
|
|
357
|
+
- `marshmallow_schema()` - Get the Marshmallow schema class
|
|
358
|
+
- `ma_load(data, **kwargs)` - Load using Marshmallow
|
|
359
|
+
- `ma_loads(json_str, **kwargs)` - Load from JSON string
|
|
360
|
+
|
|
361
|
+
**Instance Methods:**
|
|
362
|
+
- `ma_dump(**kwargs)` - Dump using Marshmallow
|
|
363
|
+
- `ma_dumps(**kwargs)` - Dump to JSON string
|
|
364
|
+
|
|
365
|
+
## License
|
|
366
|
+
|
|
367
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
pydantic_marshmallow/__init__.py,sha256=IeZH-ZcLxyy_OMfIn-IxbPRxskOnPxY94E7FLJEEBcA,2831
|
|
2
|
+
pydantic_marshmallow/bridge.py,sha256=JkDF-BozWZtzTl31RMqRHPEV_eKbeybnsuEPNdrU--Q,47688
|
|
3
|
+
pydantic_marshmallow/errors.py,sha256=slWs9m6Iid32ZUg8uxzNbFoZWFqh7ZuiG5qPlcOaBuc,5304
|
|
4
|
+
pydantic_marshmallow/field_conversion.py,sha256=xFQtR63DwTDq-hGA_8Xe8sO6lFW6BCZNmnk5oxz5B6w,4262
|
|
5
|
+
pydantic_marshmallow/py.typed,sha256=GehYepOFQ5fvmwg3UbxoFj6w91p2kWD3KUBXL_rJRUI,86
|
|
6
|
+
pydantic_marshmallow/type_mapping.py,sha256=4gFVZV7WVywyugTyiE-y7saWaHmcaPeCs0vQjBQBQ8I,5285
|
|
7
|
+
pydantic_marshmallow/validators.py,sha256=hg7ZTrjGHcyzfOtGy6T1LLGx4puRD3VSCLf0KN0PE8g,6686
|
|
8
|
+
pydantic_marshmallow-1.0.0.dist-info/licenses/LICENSE,sha256=y1B14nDO7pR7JdBNaWTLDt9MPBVRVuKZTUiRkw_eVgg,1071
|
|
9
|
+
pydantic_marshmallow-1.0.0.dist-info/METADATA,sha256=gVyLe10AtxyW4hJ9NTe43gIyPPBwigeu_BLWyopYfdg,10556
|
|
10
|
+
pydantic_marshmallow-1.0.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
11
|
+
pydantic_marshmallow-1.0.0.dist-info/top_level.txt,sha256=sQCtMe_dpBvCrrBM6YIz1UQmGSf-XjdoBUeA2uyuoh4,21
|
|
12
|
+
pydantic_marshmallow-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Michael Thomas
|
|
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.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pydantic_marshmallow
|