Benjamin-eecs/openrsi-commit-runtime-assets
0168
1diff --git a/CHANGELOG.rst b/CHANGELOG.rst2index 138d5f1..26589ca 1006443--- a/CHANGELOG.rst4+++ b/CHANGELOG.rst5@@ -6,6 +6,10 @@ Changelog6 7 Features:8 9+* Add `Parser.pre_load` as a method for allowing users to modify data before10+ schema loading, but without redefining location loaders. See advanced docs on11+ `Parser pre_load` for usage information12+13 * ``unknown`` defaults to `None` for body locations (`json`, `form` and14 `json_or_form`) (:issue:`580`).15 16diff --git a/docs/advanced.rst b/docs/advanced.rst17index 50ad01d..853fd64 10064418--- a/docs/advanced.rst19+++ b/docs/advanced.rst20@@ -435,6 +435,50 @@ To add your own parser, extend :class:`Parser <webargs.core.Parser>` and impleme21 structure_dict_pair(r, k, v)22 return r23 24+Parser pre_load25+---------------26+27+Similar to ``@pre_load`` decorated hooks on marshmallow Schemas,28+:class:`Parser <webargs.core.Parser>` classes define a method,29+`pre_load <webargs.core.Parser.pre_load>` which can30+be overridden to provide per-parser transformations of data.31+The only way to make use of `pre_load <webargs.core.Parser.pre_load>` is to32+subclass a :class:`Parser <webargs.core.Parser>` and provide an33+implementation.34+35+`pre_load <webargs.core.Parser.pre_load>` is given the data fetched from a36+location, the schema which will be used, the request object, and the location37+name which was requested. For example, to define a ``FlaskParser`` which strips38+whitespace from ``form`` and ``query`` data, one could write the following:39+40+.. code-block:: python41+42+ from webargs.flaskparser import FlaskParser43+ import typing44+45+46+ def _strip_whitespace(value):47+ if isinstance(value, str):48+ value = value.strip()49+ elif isinstance(value, typing.Mapping):50+ return {k: _strip_whitespace(value[k]) for k in value}51+ elif isinstance(value, (list, tuple)):52+ return type(value)(map(_strip_whitespace, value))53+ return value54+55+56+ class WhitspaceStrippingFlaskParser(FlaskParser):57+ def pre_load(self, location_data, *, schema, req, location):58+ if location in ("query", "form"):59+ return _strip_whitespace(location_data)60+ return location_data61+62+Note that `Parser.pre_load <webargs.core.Parser.pre_load>` is run after location63+loading but before ``Schema.load`` is called. It can therefore be called on64+multiple types of mapping objects, including65+:class:`MultiDictProxy <webargs.MultiDictProxy>`, depending on what the66+location loader returns.67+68 Returning HTTP 400 Responses69 ----------------------------70 71diff --git a/src/webargs/core.py b/src/webargs/core.py72index 3752479..e675d77 10064473--- a/src/webargs/core.py74+++ b/src/webargs/core.py75@@ -322,7 +322,10 @@ class Parser:76 location_data = self._load_location_data(77 schema=schema, req=req, location=location78 )79- data = schema.load(location_data, **load_kwargs)80+ preprocessed_data = self.pre_load(81+ location_data, schema=schema, req=req, location=location82+ )83+ data = schema.load(preprocessed_data, **load_kwargs)84 self._validate_arguments(data, validators)85 except ma.exceptions.ValidationError as error:86 self._on_validation_error(87@@ -523,6 +526,15 @@ class Parser:88 self.error_callback = func89 return func90 91+ def pre_load(92+ self, location_data: Mapping, *, schema: ma.Schema, req: Request, location: str93+ ) -> Mapping:94+ """A method of the parser which can transform data after location95+ loading is done. By default it does nothing, but users can subclass96+ parsers and override this method.97+ """98+ return location_data99+100 def _handle_invalid_json_error(101 self,102 error: typing.Union[json.JSONDecodeError, UnicodeDecodeError],103 