Repository: greyli/apiflask
Pull request #43 (2021-05-11 04:04:57)

Import and rename decorators from Marshmallow
Rename the following decorators from Marshmallow:

- pre_load -> before_load
- post_load -> after_load
- pre_dump -> before_dump
- post_dump -> after_dump
- validates -> validate
- validates_schema -> validate_schema

Not sure if it's a good idea, but this is definitely what I want to do. The four hooks are changed to match the naming style in Flask (i.e., `before_request`, `after_request`, etc.). The `validates` -> `validate` change meant to make the names more simple.

This change will introduce an API difference between APIFlask and Marshmallow, I will address these changes at the beginning of the schema docs (working in progress).



Patch:
diff --git a/apiflask/__init__.py b/apiflask/__init__.py
index d4213b0..f227368 100644
--- a/apiflask/__init__.py
+++ b/apiflask/__init__.py
@@ -5,6 +5,14 @@ if sys.platform == 'win32' and (3, 8, 0) <= sys.version_info < (3, 9, 0):  # pra
     import asyncio
     asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())  # pragma: no cover
 
+from marshmallow import pre_load as before_load
+from marshmallow import post_load as after_load
+from marshmallow import pre_dump as before_dump
+from marshmallow import post_dump as after_dump
+from marshmallow import validates as validate
+from marshmallow import validates_schema as validate_schema
+from marshmallow import ValidationError
+
 from . import fields
 from . import validators
 from .app import APIFlask
diff --git a/apiflask/app.py b/apiflask/app.py
index a157798..8e3fe0f 100644
--- a/apiflask/app.py
+++ b/apiflask/app.py
@@ -27,7 +27,7 @@ with warnings.catch_warnings():
 from werkzeug.exceptions import HTTPException as WerkzeugHTTPException
 
 from .exceptions import HTTPError
-from .exceptions import default_error_handler
+from .exceptions import _default_error_handler
 from .utils import get_reason_phrase
 from .route import route_shortcuts
 from .route import route_patch
@@ -256,7 +256,7 @@ class APIFlask(Flask):
         self.json_errors = json_errors
 
         self.spec_callback: Optional[SpecCallbackType] = None
-        self.error_callback: ErrorCallbackType = default_error_handler  # type: ignore
+        self.error_callback: ErrorCallbackType = _default_error_handler  # type: ignore
         self._spec: Optional[Union[dict, str]] = None
         self._register_openapi_blueprint()
         self._register_error_handlers()
diff --git a/apiflask/decorators.py b/apiflask/decorators.py
index 24b1d97..86ee494 100644
--- a/apiflask/decorators.py
+++ b/apiflask/decorators.py
@@ -15,7 +15,7 @@ from flask import Response
 from marshmallow import ValidationError as MarshmallowValidationError
 from webargs.flaskparser import FlaskParser as BaseFlaskParser
 
-from .exceptions import ValidationError
+from .exceptions import _ValidationError
 from .schemas import EmptySchema
 from .schemas import Schema
 from .types import DecoratedType
@@ -42,7 +42,7 @@ class FlaskParser(BaseFlaskParser):
         error_status_code: int,
         error_headers: Mapping[str, str]
     ) -> None:
-        raise ValidationError(
+        raise _ValidationError(
             error_status_code or current_app.config['VALIDATION_ERROR_STATUS_CODE'],
             current_app.config['VALIDATION_ERROR_DESCRIPTION'],
             error.messages,
diff --git a/apiflask/exceptions.py b/apiflask/exceptions.py
index bd11d1b..0825681 100644
--- a/apiflask/exceptions.py
+++ b/apiflask/exceptions.py
@@ -58,7 +58,7 @@ class HTTPError(Exception):
         self.message = get_reason_phrase(status_code) if message is None else message
 
 
-class ValidationError(HTTPError):
+class _ValidationError(HTTPError):
     """The exception used when the request validation error happened."""
 
     pass
@@ -107,7 +107,7 @@ def abort(
     raise HTTPError(status_code, message, detail, headers)
 
 
-def default_error_handler(
+def _default_error_handler(
     status_code: int,
     message: Optional[str] = None,
     detail: Optional[Any] = None,
diff --git a/apiflask/security.py b/apiflask/security.py
index 763add6..759b3fb 100644
--- a/apiflask/security.py
+++ b/apiflask/security.py
@@ -9,7 +9,7 @@ from flask import g
 from flask_httpauth import HTTPBasicAuth as BaseHTTPBasicAuth
 from flask_httpauth import HTTPTokenAuth as BaseHTTPTokenAuth
 
-from .exceptions import default_error_handler
+from .exceptions import _default_error_handler
 
 
 class _AuthBase:
@@ -31,7 +31,7 @@ def handle_auth_error(
     This handler will return JSON response when `app.json_errors` is `True` (default).
     """
     if current_app.json_errors:
-        return default_error_handler(status_code)
+        return _default_error_handler(status_code)
     return 'Unauthorized Access', status_code
 
 


Test patch:
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
index 9dbcc82..2acd5a1 100644
--- a/tests/test_exceptions.py
+++ b/tests/test_exceptions.py
@@ -2,7 +2,7 @@ import pytest
 
 from apiflask.exceptions import abort
 from apiflask.exceptions import HTTPError
-from apiflask.exceptions import default_error_handler
+from apiflask.exceptions import _default_error_handler
 
 
 @pytest.mark.parametrize('kwargs', [
@@ -62,7 +62,7 @@ def test_abort(app, client, kwargs):
     {'message': 'bad', 'detail': {'location': 'json'}, 'headers': {'X-FOO': 'bar'}}
 ])
 def test_default_error_handler(kwargs):
-    rv = default_error_handler(400, **kwargs)
+    rv = _default_error_handler(400, **kwargs)
     assert rv[1] == 400
     if 'message' not in kwargs:
         assert rv[0]['message'] == 'Bad Request'