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.
@@ -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
+ [![CI](https://github.com/mockodin/pydantic-marshmallow/actions/workflows/ci.yml/badge.svg)](https://github.com/mockodin/pydantic-marshmallow/actions/workflows/ci.yml)
62
+ [![PyPI version](https://badge.fury.io/py/pydantic-marshmallow.svg)](https://badge.fury.io/py/pydantic-marshmallow)
63
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
64
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -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