flask-marshmallow 1.2.1__py3-none-any.whl → 1.4.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.
@@ -9,7 +9,15 @@ with your Flask application.
9
9
  import typing
10
10
  import warnings
11
11
 
12
- from marshmallow import exceptions, pprint
12
+ from marshmallow import exceptions
13
+
14
+ try:
15
+ # Available in marshmallow 3 only
16
+ from marshmallow import pprint # noqa: F401
17
+ except ImportError:
18
+ _has_pprint = False
19
+ else:
20
+ _has_pprint = True
13
21
  from marshmallow import fields as base_fields
14
22
 
15
23
  from . import fields
@@ -41,8 +49,9 @@ __all__ = [
41
49
  "Schema",
42
50
  "fields",
43
51
  "exceptions",
44
- "pprint",
45
52
  ]
53
+ if _has_pprint:
54
+ __all__.append("pprint")
46
55
 
47
56
  EXTENSION_NAME = "flask-marshmallow"
48
57
 
@@ -75,9 +84,8 @@ class Marshmallow:
75
84
  You can declare schema like so::
76
85
 
77
86
  class BookSchema(ma.Schema):
78
- class Meta:
79
- fields = ("id", "title", "author", "links")
80
-
87
+ id = ma.Integer(dump_only=True)
88
+ title = ma.String(required=True)
81
89
  author = ma.Nested(AuthorSchema)
82
90
 
83
91
  links = ma.Hyperlinks(
@@ -126,6 +134,12 @@ class Marshmallow:
126
134
  # If using Flask-SQLAlchemy, attach db.session to SQLAlchemySchema
127
135
  if has_sqla and "sqlalchemy" in app.extensions:
128
136
  db = app.extensions["sqlalchemy"]
129
- self.SQLAlchemySchema.OPTIONS_CLASS.session = db.session
130
- self.SQLAlchemyAutoSchema.OPTIONS_CLASS.session = db.session
137
+ SQLAlchemySchemaOpts = typing.cast(
138
+ sqla.SQLAlchemySchemaOpts, self.SQLAlchemySchema.OPTIONS_CLASS
139
+ )
140
+ SQLAlchemySchemaOpts.session = db.session
141
+ SQLAlchemyAutoSchemaOpts = typing.cast(
142
+ sqla.SQLAlchemyAutoSchemaOpts, self.SQLAlchemySchema.OPTIONS_CLASS
143
+ )
144
+ SQLAlchemyAutoSchemaOpts.session = db.session
131
145
  app.extensions[EXTENSION_NAME] = self
@@ -8,6 +8,8 @@ See the `marshmallow.fields` module for the list of all fields available from th
8
8
  marshmallow library.
9
9
  """
10
10
 
11
+ from __future__ import annotations
12
+
11
13
  import re
12
14
  import typing
13
15
  from collections.abc import Sequence
@@ -29,7 +31,7 @@ __all__ = [
29
31
  _tpl_pattern = re.compile(r"\s*<\s*(\S*)\s*>\s*")
30
32
 
31
33
 
32
- def _tpl(val: str) -> typing.Optional[str]:
34
+ def _tpl(val: str) -> str | None:
33
35
  """Return value within ``< >`` if possible, else return ``None``."""
34
36
  match = _tpl_pattern.match(val)
35
37
  if match:
@@ -95,7 +97,7 @@ class URLFor(fields.Field):
95
97
  def __init__(
96
98
  self,
97
99
  endpoint: str,
98
- values: typing.Optional[typing.Dict[str, typing.Any]] = None,
100
+ values: dict[str, typing.Any] | None = None,
99
101
  **kwargs,
100
102
  ):
101
103
  self.endpoint = endpoint
@@ -117,7 +119,7 @@ class URLFor(fields.Field):
117
119
  param_values[name] = attribute_value
118
120
  else:
119
121
  raise AttributeError(
120
- f"{attr_name!r} is not a valid " f"attribute of {obj!r}"
122
+ f"{attr_name!r} is not a valid attribute of {obj!r}"
121
123
  )
122
124
  else:
123
125
  param_values[name] = attr_tpl
@@ -133,7 +135,7 @@ class AbsoluteURLFor(URLFor):
133
135
  def __init__(
134
136
  self,
135
137
  endpoint: str,
136
- values: typing.Optional[typing.Dict[str, typing.Any]] = None,
138
+ values: dict[str, typing.Any] | None = None,
137
139
  **kwargs,
138
140
  ):
139
141
  if values:
@@ -146,9 +148,7 @@ class AbsoluteURLFor(URLFor):
146
148
  AbsoluteUrlFor = AbsoluteURLFor
147
149
 
148
150
 
149
- def _rapply(
150
- d: typing.Union[dict, typing.Iterable], func: typing.Callable, *args, **kwargs
151
- ):
151
+ def _rapply(d: dict | typing.Iterable, func: typing.Callable, *args, **kwargs):
152
152
  """Apply a function to all values in a dictionary or
153
153
  list of dictionaries, recursively.
154
154
  """
@@ -201,7 +201,7 @@ class Hyperlinks(fields.Field):
201
201
 
202
202
  _CHECK_ATTRIBUTE = False
203
203
 
204
- def __init__(self, schema: typing.Dict[str, typing.Union[URLFor, str]], **kwargs):
204
+ def __init__(self, schema: dict[str, URLFor | str], **kwargs):
205
205
  self.schema = schema
206
206
  fields.Field.__init__(self, **kwargs)
207
207
 
@@ -229,8 +229,8 @@ class File(fields.Field):
229
229
  def deserialize(
230
230
  self,
231
231
  value: typing.Any,
232
- attr: typing.Optional[str] = None,
233
- data: typing.Optional[typing.Mapping[str, typing.Any]] = None,
232
+ attr: str | None = None,
233
+ data: typing.Mapping[str, typing.Any] | None = None,
234
234
  **kwargs,
235
235
  ):
236
236
  if isinstance(value, Sequence) and len(value) == 0:
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import typing
2
4
 
3
5
  import flask
@@ -14,8 +16,8 @@ class Schema(ma.Schema):
14
16
  """
15
17
 
16
18
  def jsonify(
17
- self, obj: typing.Any, many: typing.Optional[bool] = None, *args, **kwargs
18
- ) -> "Response":
19
+ self, obj: typing.Any, many: bool | None = None, *args, **kwargs
20
+ ) -> Response:
19
21
  """Return a JSON response containing the serialized data.
20
22
 
21
23
 
flask_marshmallow/sqla.py CHANGED
@@ -8,6 +8,8 @@ Integration with Flask-SQLAlchemy and marshmallow-sqlalchemy. Provides
8
8
  that use the scoped session from Flask-SQLAlchemy.
9
9
  """
10
10
 
11
+ from __future__ import annotations
12
+
11
13
  from urllib import parse
12
14
 
13
15
  import marshmallow_sqlalchemy as msqla
@@ -5,6 +5,8 @@ flask_marshmallow.validate
5
5
  Custom validation classes for various types of data.
6
6
  """
7
7
 
8
+ from __future__ import annotations
9
+
8
10
  import io
9
11
  import os
10
12
  import re
@@ -91,11 +93,11 @@ class FileSize(Validator):
91
93
 
92
94
  def __init__(
93
95
  self,
94
- min: typing.Optional[str] = None,
95
- max: typing.Optional[str] = None,
96
+ min: str | None = None,
97
+ max: str | None = None,
96
98
  min_inclusive: bool = True,
97
99
  max_inclusive: bool = True,
98
- error: typing.Optional[str] = None,
100
+ error: str | None = None,
99
101
  ):
100
102
  self.min = min
101
103
  self.max = max
@@ -171,14 +173,14 @@ class FileType(Validator):
171
173
  def __init__(
172
174
  self,
173
175
  accept: typing.Iterable[str],
174
- error: typing.Optional[str] = None,
176
+ error: str | None = None,
175
177
  ):
176
178
  self.allowed_types = {ext.lower() for ext in accept}
177
179
  self.error = error or self.default_message
178
180
 
179
181
  def _format_error(self, value):
180
182
  return (self.error or self.default_message).format(
181
- input=value, extensions="".join(self.allowed_types)
183
+ input=value, extensions=",".join(self.allowed_types)
182
184
  )
183
185
 
184
186
  def __call__(self, value):
@@ -1,29 +1,30 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: flask-marshmallow
3
- Version: 1.2.1
3
+ Version: 1.4.0
4
4
  Summary: Flask + marshmallow for beautiful APIs
5
- Maintainer-email: Steven Loria <sloria1@gmail.com>, Stephen Rosen <sirosen0@gmail.com>
6
- Requires-Python: >=3.8
5
+ Maintainer-email: Steven Loria <oss@stevenloria.com>, Stephen Rosen <sirosen0@gmail.com>
6
+ Requires-Python: >=3.10
7
7
  Description-Content-Type: text/x-rst
8
8
  Classifier: Environment :: Web Environment
9
9
  Classifier: Intended Audience :: Developers
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Natural Language :: English
12
12
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.8
14
- Classifier: Programming Language :: Python :: 3.9
15
13
  Classifier: Programming Language :: Python :: 3.10
16
14
  Classifier: Programming Language :: Python :: 3.11
17
15
  Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
18
  Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
19
+ License-File: LICENSE
19
20
  Requires-Dist: Flask>=2.2
20
21
  Requires-Dist: marshmallow>=3.0.0
21
22
  Requires-Dist: flask-marshmallow[tests] ; extra == "dev"
22
23
  Requires-Dist: tox ; extra == "dev"
23
- Requires-Dist: pre-commit~=3.5 ; extra == "dev"
24
+ Requires-Dist: pre-commit>=4.5,<5.0 ; extra == "dev"
24
25
  Requires-Dist: marshmallow-sqlalchemy>=0.19.0 ; extra == "docs"
25
- Requires-Dist: Sphinx==7.2.6 ; extra == "docs"
26
- Requires-Dist: sphinx-issues==4.0.0 ; extra == "docs"
26
+ Requires-Dist: Sphinx==9.1.0 ; extra == "docs"
27
+ Requires-Dist: sphinx-issues==5.0.1 ; extra == "docs"
27
28
  Requires-Dist: flask-sqlalchemy>=3.0.0 ; extra == "sqlalchemy"
28
29
  Requires-Dist: marshmallow-sqlalchemy>=0.29.0 ; extra == "sqlalchemy"
29
30
  Requires-Dist: flask-marshmallow[sqlalchemy] ; extra == "tests"
@@ -39,7 +40,7 @@ Provides-Extra: tests
39
40
  Flask-Marshmallow
40
41
  *****************
41
42
 
42
- |pypi-package| |build-status| |docs| |marshmallow3|
43
+ |pypi-package| |build-status| |docs| |marshmallow-support|
43
44
 
44
45
  Flask + marshmallow for beautiful APIs
45
46
  ======================================
@@ -82,9 +83,8 @@ Define your output format with marshmallow.
82
83
 
83
84
 
84
85
  class UserSchema(ma.Schema):
85
- class Meta:
86
- # Fields to expose
87
- fields = ("email", "date_created", "_links")
86
+ email = ma.Email()
87
+ date_created = ma.DateTime()
88
88
 
89
89
  # Smart hyperlinking
90
90
  _links = ma.Hyperlinks(
@@ -164,7 +164,7 @@ MIT licensed. See the bundled `LICENSE <https://github.com/marshmallow-code/flas
164
164
  :target: https://flask-marshmallow.readthedocs.io/
165
165
  :alt: Documentation
166
166
 
167
- .. |marshmallow3| image:: https://badgen.net/badge/marshmallow/3
167
+ .. |marshmallow-support| image:: https://badgen.net/badge/marshmallow/3,4?list=1
168
168
  :target: https://marshmallow.readthedocs.io/en/latest/upgrading.html
169
- :alt: marshmallow 3 compatible
169
+ :alt: marshmallow 3|4 compatible
170
170
 
@@ -0,0 +1,10 @@
1
+ flask_marshmallow/__init__.py,sha256=z1T-yR1vgxKgU_QtdJmJgkJEFgKInIn1piaaOfb9ndw,4131
2
+ flask_marshmallow/fields.py,sha256=_aDs2dWM5CV2xigge_b4Qoz7LGam5gJoTLPlG0frD50,7865
3
+ flask_marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ flask_marshmallow/schema.py,sha256=qC6jF_peb8WvQAJpe14MQaLmqRahAReoP7GKcC4nNfI,1436
5
+ flask_marshmallow/sqla.py,sha256=RXiV5EZwg8g3XWN5ZsqOK3xrhmZ5FlgeVmzwDExC1LU,3984
6
+ flask_marshmallow/validate.py,sha256=cUsavS9Hsdb9yQ_WKvswbVjEMfD92GGDVm7yfmU-4W4,6813
7
+ flask_marshmallow-1.4.0.dist-info/licenses/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
8
+ flask_marshmallow-1.4.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
9
+ flask_marshmallow-1.4.0.dist-info/METADATA,sha256=92zlOeitEYTujBPEvK1HxRMYXMsqEYDmsdOS1CDLdzE,5203
10
+ flask_marshmallow-1.4.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: flit 3.9.0
2
+ Generator: flit 3.12.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,10 +0,0 @@
1
- flask_marshmallow/__init__.py,sha256=IsYMbL7JZL1yc1P0EKVfpxokIMlnKKVNMcSwhHfu29w,3678
2
- flask_marshmallow/fields.py,sha256=Z-v60FhOe-HlupA_tGhZMtS4p4b9i4LFbTbCgDCQ5-4,7936
3
- flask_marshmallow/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- flask_marshmallow/schema.py,sha256=Z6uJVkqi-gq1QfdPbPuy5Fw3UnXGE9vKiD6IJkPOMR4,1412
5
- flask_marshmallow/sqla.py,sha256=VN4aH5pm1HvyepeV6AHtipTAK_Mz_zLA-0IulsObhCk,3948
6
- flask_marshmallow/validate.py,sha256=KRJus6GpPC7MZGFjDidhnNjI3tc6_y9PPQ-Pcmik18I,6816
7
- flask_marshmallow-1.2.1.dist-info/LICENSE,sha256=kGtdkFHkJhRMsXOtkRZnuOvQWpxYTCwmwTWzKj7RIAE,1064
8
- flask_marshmallow-1.2.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
9
- flask_marshmallow-1.2.1.dist-info/METADATA,sha256=E5EDVQ1awnti6hs2oQPuBu1B5xAV19cfvW6kiUqbXH8,5190
10
- flask_marshmallow-1.2.1.dist-info/RECORD,,