Skip to content

Commit 54affe8

Browse files
committed
Remove support for marshmallow2
Anywhere that version dispatch was used, switch to the ma3 version of the code. Tests skipped on marshmallow3 are dropped. Remove dict2schema, since it is now redundant with Schema.from_dict . Update the changelog and docstrings around `unknown=...` to remove note that it only works on marshmallow3. Remove any documentation which notes a marshmallow2 (vs ma3) discrepancy or a way of getting the same behavior out of both versions. Update readme badge to ma3 only. tox and azure pipelines config are altered to drop marshmallow2 builds. Update `setup.py` to require `marshmallow>=3.0.0` closes #540
1 parent 3391b69 commit 54affe8

27 files changed

Lines changed: 142 additions & 407 deletions

CHANGELOG.rst

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,27 @@ Changelog
44
7.0.0 (Unreleased)
55
******************
66

7+
Refactoring:
8+
9+
* *Backwards-incompatible*: Remove support for marshmallow2 (:issue:`539`)
10+
11+
* *Backwards-incompatible*: Remove `dict2schema`
12+
13+
Users desiring the `dict2schema` functionality may now rely upon
14+
`marshmallow.Schema.from_dict`. Rewrite any code using `dict2schema` like so:
15+
16+
.. code-block:: python
17+
18+
import marshmallow as ma
19+
20+
# webargs 6.x and older
21+
from webargs import dict2schema
22+
23+
myschema = dict2schema({"q1", ma.fields.Int()})
24+
25+
# webargs 7.x
26+
myschema = ma.Schema.from_dict({"q1", ma.fields.Int()})
27+
728
Features:
829

930
* Add a new ``unknown`` parameter to ``Parser.parse``, ``Parser.use_args``, and
@@ -17,7 +38,7 @@ This allows usages like
1738
1839
import marshmallow as ma
1940
20-
# marshmallow 3 only, for use of ``unknown`` and ``EXCLUDE``
41+
2142
@parser.use_kwargs(
2243
{"q1": ma.fields.Int(), "q2": ma.fields.Int()}, location="query", unknown=ma.EXCLUDE
2344
)

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ webargs
1414
:target: https://webargs.readthedocs.io/
1515
:alt: Documentation
1616

17-
.. image:: https://badgen.net/badge/marshmallow/2,3?list=1
17+
.. image:: https://badgen.net/badge/marshmallow/3
1818
:target: https://marshmallow.readthedocs.io/en/latest/upgrading.html
19-
:alt: marshmallow 2/3 compatible
19+
:alt: marshmallow 3 compatible
2020

2121
.. image:: https://badgen.net/badge/code%20style/black/000
2222
:target: https://github.com/ambv/black

azure-pipelines.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,13 @@ jobs:
2727
toxenvs:
2828
- lint
2929

30-
- py35-marshmallow2
31-
- py35-marshmallow3
30+
- py35
3231

33-
- py36-marshmallow3
32+
- py36
3433

35-
- py37-marshmallow3
34+
- py37
3635

37-
- py38-marshmallow2
38-
- py38-marshmallow3
36+
- py38
3937

4038
- py38-marshmallowdev
4139

docs/advanced.rst

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,6 @@ When you need more flexibility in defining input schemas, you can pass a marshma
107107
last_name = fields.Str(missing="")
108108
date_registered = fields.DateTime(dump_only=True)
109109
110-
# NOTE: Uncomment below two lines if you're using marshmallow 2
111-
# class Meta:
112-
# strict = True
113-
114110
115111
@use_args(UserSchema())
116112
def profile_view(args):
@@ -131,9 +127,6 @@ When you need more flexibility in defining input schemas, you can pass a marshma
131127
username = args["username"]
132128
# ...
133129
134-
.. warning::
135-
If you're using marshmallow 2, you should always set ``strict=True`` (either as a ``class Meta`` option or in the Schema's constructor) when passing a schema to webargs. This will ensure that the parser's error handler is invoked when expected.
136-
137130
138131
When to avoid `use_kwargs`
139132
--------------------------

docs/quickstart.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ Arguments are specified as a dictionary of name -> :class:`Field <marshmallow.fi
2525
"languages": fields.DelimitedList(fields.Str()),
2626
# When value is keyed on a variable-unsafe name
2727
# or you want to rename a key
28-
"user_type": fields.Str(load_from="user-type"),
29-
# OR, on marshmallow 3
30-
# "user_type": fields.Str(data_key="user-type"),
28+
"user_type": fields.Str(data_key="user-type"),
3129
}
3230
3331
.. note::

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def read(fname):
7070
url="https://github.com/marshmallow-code/webargs",
7171
packages=find_packages("src"),
7272
package_dir={"": "src"},
73-
install_requires=["marshmallow>=2.15.2"],
73+
install_requires=["marshmallow>=3.0.0"],
7474
extras_require=EXTRAS_REQUIRE,
7575
license="MIT",
7676
zip_safe=False,

src/webargs/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
from marshmallow import validate
66

77
from webargs.core import ValidationError
8-
from webargs.dict2schema import dict2schema
98
from webargs import fields
109

1110
__version__ = "7.0.0-dev"
1211
__version_info__ = tuple(LooseVersion(__version__).version)
13-
__all__ = ("dict2schema", "ValidationError", "fields", "missing", "validate")
12+
__all__ = ("ValidationError", "fields", "missing", "validate")

src/webargs/asyncparser.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from marshmallow.fields import Field
1010
import marshmallow as ma
1111

12-
from webargs.compat import MARSHMALLOW_VERSION_INFO
1312
from webargs import core
1413

1514
Request = typing.TypeVar("Request")
@@ -41,9 +40,7 @@ async def parse(
4140
req = req if req is not None else self.get_default_request()
4241
location = location or self.location
4342
unknown = unknown or self.unknown
44-
load_kwargs = (
45-
{"unknown": unknown} if MARSHMALLOW_VERSION_INFO[0] >= 3 and unknown else {}
46-
)
43+
load_kwargs = {"unknown": unknown}
4744
if req is None:
4845
raise ValueError("Must pass req object")
4946
data = None
@@ -53,8 +50,7 @@ async def parse(
5350
location_data = await self._load_location_data(
5451
schema=schema, req=req, location=location
5552
)
56-
result = schema.load(location_data, **load_kwargs)
57-
data = result.data if core.MARSHMALLOW_VERSION_INFO[0] < 3 else result
53+
data = schema.load(location_data, **load_kwargs)
5854
self._validate_arguments(data, validators)
5955
except ma.exceptions.ValidationError as error:
6056
await self._on_validation_error(
@@ -132,7 +128,7 @@ def use_args(
132128
# Optimization: If argmap is passed as a dictionary, we only need
133129
# to generate a Schema once
134130
if isinstance(argmap, Mapping):
135-
argmap = core.dict2schema(argmap, schema_class=self.schema_class)()
131+
argmap = self.schema_class.from_dict(argmap)()
136132

137133
def decorator(func: typing.Callable) -> typing.Callable:
138134
req_ = request_obj

src/webargs/compat.py

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/webargs/core.py

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,20 @@
22
import inspect
33
import typing
44
import logging
5-
import warnings
65
from collections.abc import Mapping
76
import json
87

98
import marshmallow as ma
109
from marshmallow import ValidationError
1110
from marshmallow.utils import missing
1211

13-
from webargs.compat import MARSHMALLOW_VERSION_INFO
14-
from webargs.dict2schema import dict2schema
1512
from webargs.fields import DelimitedList
1613

1714
logger = logging.getLogger(__name__)
1815

1916

2017
__all__ = [
2118
"ValidationError",
22-
"dict2schema",
2319
"is_multiple",
2420
"Parser",
2521
"missing",
@@ -214,13 +210,7 @@ def _get_schema(self, argmap, req):
214210
elif callable(argmap):
215211
schema = argmap(req)
216212
else:
217-
schema = dict2schema(argmap, schema_class=self.schema_class)()
218-
if MARSHMALLOW_VERSION_INFO[0] < 3 and not schema.strict:
219-
warnings.warn(
220-
"It is highly recommended that you set strict=True on your schema "
221-
"so that the parser's error handler will be invoked when expected.",
222-
UserWarning,
223-
)
213+
schema = self.schema_class.from_dict(argmap)()
224214
return schema
225215

226216
def parse(
@@ -245,7 +235,7 @@ def parse(
245235
default, that means one of ``('json', 'query', 'querystring',
246236
'form', 'headers', 'cookies', 'files', 'json_or_form')``.
247237
:param str unknown: A value to pass for ``unknown`` when calling the
248-
schema's ``load`` method (marshmallow 3 only).
238+
schema's ``load`` method.
249239
:param callable validate: Validation function or list of validation functions
250240
that receives the dictionary of parsed arguments. Validator either returns a
251241
boolean or raises a :exc:`ValidationError`.
@@ -259,9 +249,7 @@ def parse(
259249
req = req if req is not None else self.get_default_request()
260250
location = location or self.location
261251
unknown = unknown or self.unknown
262-
load_kwargs = (
263-
{"unknown": unknown} if MARSHMALLOW_VERSION_INFO[0] >= 3 and unknown else {}
264-
)
252+
load_kwargs = {"unknown": unknown}
265253
if req is None:
266254
raise ValueError("Must pass req object")
267255
data = None
@@ -271,8 +259,7 @@ def parse(
271259
location_data = self._load_location_data(
272260
schema=schema, req=req, location=location
273261
)
274-
result = schema.load(location_data, **load_kwargs)
275-
data = result.data if MARSHMALLOW_VERSION_INFO[0] < 3 else result
262+
data = schema.load(location_data, **load_kwargs)
276263
self._validate_arguments(data, validators)
277264
except ma.exceptions.ValidationError as error:
278265
self._on_validation_error(
@@ -344,7 +331,7 @@ def greet(args):
344331
which accepts a request and returns a `marshmallow.Schema`.
345332
:param str location: Where on the request to load values.
346333
:param str unknown: A value to pass for ``unknown`` when calling the
347-
schema's ``load`` method (marshmallow 3 only).
334+
schema's ``load`` method.
348335
:param bool as_kwargs: Whether to insert arguments as keyword arguments.
349336
:param callable validate: Validation function that receives the dictionary
350337
of parsed arguments. If the function returns ``False``, the parser
@@ -359,7 +346,7 @@ def greet(args):
359346
# Optimization: If argmap is passed as a dictionary, we only need
360347
# to generate a Schema once
361348
if isinstance(argmap, Mapping):
362-
argmap = dict2schema(argmap, schema_class=self.schema_class)()
349+
argmap = self.schema_class.from_dict(argmap)()
363350

364351
def decorator(func):
365352
req_ = request_obj

0 commit comments

Comments
 (0)