flask-marshmallow 0.14.0__tar.gz → 1.0.0__tar.gz

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.
Files changed (50) hide show
  1. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/CHANGELOG.rst +44 -2
  2. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/CONTRIBUTING.rst +1 -1
  3. flask_marshmallow-1.0.0/PKG-INFO +171 -0
  4. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/README.rst +8 -8
  5. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_templates/side-primary.html +1 -1
  6. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_templates/side-secondary.html +1 -1
  7. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/conf.py +5 -8
  8. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/index.rst +5 -1
  9. flask_marshmallow-1.0.0/pyproject.toml +66 -0
  10. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/src/flask_marshmallow/__init__.py +19 -13
  11. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/src/flask_marshmallow/fields.py +80 -14
  12. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/src/flask_marshmallow/schema.py +1 -7
  13. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/src/flask_marshmallow/sqla.py +12 -20
  14. flask_marshmallow-1.0.0/src/flask_marshmallow/validate.py +183 -0
  15. flask_marshmallow-1.0.0/tests/__init__.py +0 -0
  16. flask_marshmallow-1.0.0/tests/conftest.py +112 -0
  17. flask_marshmallow-1.0.0/tests/markers.py +9 -0
  18. flask_marshmallow-1.0.0/tests/test_core.py +64 -0
  19. flask_marshmallow-1.0.0/tests/test_fields.py +169 -0
  20. flask_marshmallow-1.0.0/tests/test_io.py +0 -0
  21. flask_marshmallow-1.0.0/tests/test_sqla.py +288 -0
  22. flask_marshmallow-1.0.0/tests/test_validate.py +107 -0
  23. flask_marshmallow-1.0.0/tox.ini +40 -0
  24. flask-marshmallow-0.14.0/MANIFEST.in +0 -5
  25. flask-marshmallow-0.14.0/PKG-INFO +0 -163
  26. flask-marshmallow-0.14.0/setup.cfg +0 -13
  27. flask-marshmallow-0.14.0/setup.py +0 -84
  28. flask-marshmallow-0.14.0/src/flask_marshmallow/compat.py +0 -9
  29. flask-marshmallow-0.14.0/src/flask_marshmallow.egg-info/PKG-INFO +0 -163
  30. flask-marshmallow-0.14.0/src/flask_marshmallow.egg-info/SOURCES.txt +0 -37
  31. flask-marshmallow-0.14.0/src/flask_marshmallow.egg-info/dependency_links.txt +0 -1
  32. flask-marshmallow-0.14.0/src/flask_marshmallow.egg-info/not-zip-safe +0 -1
  33. flask-marshmallow-0.14.0/src/flask_marshmallow.egg-info/requires.txt +0 -52
  34. flask-marshmallow-0.14.0/src/flask_marshmallow.egg-info/top_level.txt +0 -1
  35. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/LICENSE +0 -0
  36. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/Makefile +0 -0
  37. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_static/logo.png +0 -0
  38. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/LICENSE +0 -0
  39. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/README +0 -0
  40. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/flask/layout.html +0 -0
  41. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/flask/relations.html +0 -0
  42. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/flask/static/flasky.css_t +0 -0
  43. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/flask/theme.conf +0 -0
  44. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/flask_small/layout.html +0 -0
  45. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/flask_small/static/flasky.css_t +0 -0
  46. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/flask_small/theme.conf +0 -0
  47. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/_themes/flask_theme_support.py +7 -7
  48. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/changelog.rst +0 -0
  49. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/license.rst +0 -0
  50. {flask-marshmallow-0.14.0 → flask_marshmallow-1.0.0}/docs/make.bat +0 -0
@@ -1,12 +1,54 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ 1.0.0 (2024-01-16)
5
+ ******************
6
+
7
+ Features:
8
+
9
+ * Add field ``fields.File``, ``validate.FileType``, and ``validate.FileSize``
10
+ for deserializing uploaded files (:issue:`280`, :pr:`282`).
11
+ Thanks :user:`uncle-lv` for the PR
12
+ * Add field ``Config`` for serializing Flask configuration values (:issue:`280`, :pr:`281`).
13
+ Thanks :user:`greyli` for the PR.
14
+
15
+ Support:
16
+
17
+ * Support marshmallow-sqlalchemy>=0.29.0.
18
+ * Test against Python 3.12.
19
+ * Drop support for Python 3.7.
20
+
21
+ Other changes:
22
+
23
+ * *Backwards-incompatible*: Remove ```flask_marshmallow.__version__``
24
+ and ``flask_marshmallow.__version_info__`` attributes (:pr:`284`).
25
+ Use feature detection or ``importlib.metadata.version("flask-marshmallow")`` instead.
26
+
27
+ 0.15.0 (2023-04-05)
28
+ *******************
29
+
30
+ * Changes to supported software versions.
31
+
32
+ * python3.6 or later and marshmallow>=3.0.0 are now required
33
+ * Add support for python3.11
34
+ * For ``sqlalchemy`` integration, marshmallow-sqlalchemy>=0.28.2 and
35
+ flask-sqlalchemy>=3.0.0 are now required
36
+
37
+ * *Backwards-incompatible*: ``URLFor`` and ``AbsoluteURLFor`` now do not accept
38
+ parameters for ``flask.url_for`` as top-level parameters. They must always be
39
+ passed in the ``values`` dictionary, as explained in the v0.14.0 changelog.
40
+
41
+ Bug fixes:
42
+
43
+ * Address distutils deprecation warning in Python 3.10 (:pr:`242`).
44
+ Thanks :user:`GabrielLins64` for the PR.
45
+
4
46
  0.14.0 (2020-09-27)
5
47
  *******************
6
48
 
7
49
  * Add ``values`` argument to ``URLFor`` and ``AbsoluteURLFor`` for passing values to ``flask.url_for``.
8
- This prevents unrelated parameters from getting passed (:issue:`52`, :issue:`67`).
9
- Thanks :user:`AlrasheedA` for the PR.
50
+ This prevents unrelated parameters from getting passed (:issue:`52`, :issue:`67`).
51
+ Thanks :user:`AlrasheedA` for the PR.
10
52
 
11
53
  Deprecation:
12
54
 
@@ -108,7 +108,7 @@ To run syntax checks: ::
108
108
 
109
109
  $ tox -e lint
110
110
 
111
- (Optional) To run tests on Python 2.7, 3.5, 3.6, and 3.7 virtual environments (must have each interpreter installed): ::
111
+ (Optional) To run tests in all supported Python versions in their own virtual environments (must have each interpreter installed): ::
112
112
 
113
113
  $ tox
114
114
 
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.1
2
+ Name: flask-marshmallow
3
+ Version: 1.0.0
4
+ Summary: Flask + marshmallow for beautiful APIs
5
+ Maintainer-email: Steven Loria <sloria1@gmail.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/x-rst
8
+ Classifier: Environment :: Web Environment
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Natural Language :: English
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.8
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
19
+ Requires-Dist: Flask
20
+ Requires-Dist: marshmallow>=3.0.0
21
+ Requires-Dist: packaging>=17.0
22
+ Requires-Dist: flask-marshmallow[tests] ; extra == "dev"
23
+ Requires-Dist: tox ; extra == "dev"
24
+ Requires-Dist: pre-commit~=3.5 ; extra == "dev"
25
+ Requires-Dist: marshmallow-sqlalchemy>=0.19.0 ; extra == "docs"
26
+ Requires-Dist: Sphinx==7.2.6 ; extra == "docs"
27
+ Requires-Dist: sphinx-issues==3.0.1 ; extra == "docs"
28
+ Requires-Dist: flask-sqlalchemy>=3.0.0 ; extra == "sqlalchemy"
29
+ Requires-Dist: marshmallow-sqlalchemy>=0.29.0 ; extra == "sqlalchemy"
30
+ Requires-Dist: flask-marshmallow[sqlalchemy] ; extra == "tests"
31
+ Requires-Dist: pytest ; extra == "tests"
32
+ Project-URL: Funding, https://opencollective.com/marshmallow
33
+ Project-URL: Issues, https://github.com/marshmallow-code/flask-marshmallow/issues
34
+ Provides-Extra: dev
35
+ Provides-Extra: docs
36
+ Provides-Extra: sqlalchemy
37
+ Provides-Extra: tests
38
+
39
+ *****************
40
+ Flask-Marshmallow
41
+ *****************
42
+
43
+ |pypi-package| |build-status| |docs| |marshmallow3|
44
+
45
+ Flask + marshmallow for beautiful APIs
46
+ ======================================
47
+
48
+ Flask-Marshmallow is a thin integration layer for `Flask`_ (a Python web framework) and `marshmallow`_ (an object serialization/deserialization library) that adds additional features to marshmallow, including URL and Hyperlinks fields for HATEOAS-ready APIs. It also (optionally) integrates with `Flask-SQLAlchemy <http://flask-sqlalchemy.pocoo.org/>`_.
49
+
50
+ Get it now
51
+ ----------
52
+ ::
53
+
54
+ pip install flask-marshmallow
55
+
56
+
57
+ Create your app.
58
+
59
+ .. code-block:: python
60
+
61
+ from flask import Flask
62
+ from flask_marshmallow import Marshmallow
63
+
64
+ app = Flask(__name__)
65
+ ma = Marshmallow(app)
66
+
67
+ Write your models.
68
+
69
+ .. code-block:: python
70
+
71
+ from your_orm import Model, Column, Integer, String, DateTime
72
+
73
+
74
+ class User(Model):
75
+ email = Column(String)
76
+ password = Column(String)
77
+ date_created = Column(DateTime, auto_now_add=True)
78
+
79
+
80
+ Define your output format with marshmallow.
81
+
82
+ .. code-block:: python
83
+
84
+
85
+ class UserSchema(ma.Schema):
86
+ class Meta:
87
+ # Fields to expose
88
+ fields = ("email", "date_created", "_links")
89
+
90
+ # Smart hyperlinking
91
+ _links = ma.Hyperlinks(
92
+ {
93
+ "self": ma.URLFor("user_detail", values=dict(id="<id>")),
94
+ "collection": ma.URLFor("users"),
95
+ }
96
+ )
97
+
98
+
99
+ user_schema = UserSchema()
100
+ users_schema = UserSchema(many=True)
101
+
102
+
103
+ Output the data in your views.
104
+
105
+ .. code-block:: python
106
+
107
+ @app.route("/api/users/")
108
+ def users():
109
+ all_users = User.all()
110
+ return users_schema.dump(all_users)
111
+
112
+
113
+ @app.route("/api/users/<id>")
114
+ def user_detail(id):
115
+ user = User.get(id)
116
+ return user_schema.dump(user)
117
+
118
+
119
+ # {
120
+ # "email": "fred@queen.com",
121
+ # "date_created": "Fri, 25 Apr 2014 06:02:56 -0000",
122
+ # "_links": {
123
+ # "self": "/api/users/42",
124
+ # "collection": "/api/users/"
125
+ # }
126
+ # }
127
+
128
+
129
+ http://flask-marshmallow.readthedocs.io/
130
+ ========================================
131
+
132
+ Learn More
133
+ ==========
134
+
135
+ To learn more about marshmallow, check out its `docs <http://marshmallow.readthedocs.io/en/latest/>`_.
136
+
137
+
138
+
139
+ Project Links
140
+ =============
141
+
142
+ - Docs: https://flask-marshmallow.readthedocs.io/
143
+ - Changelog: http://flask-marshmallow.readthedocs.io/en/latest/changelog.html
144
+ - PyPI: https://pypi.org/project/flask-marshmallow/
145
+ - Issues: https://github.com/marshmallow-code/flask-marshmallow/issues
146
+
147
+ License
148
+ =======
149
+
150
+ MIT licensed. See the bundled `LICENSE <https://github.com/marshmallow-code/flask-marshmallow/blob/master/LICENSE>`_ file for more details.
151
+
152
+
153
+ .. _Flask: http://flask.pocoo.org
154
+ .. _marshmallow: http://marshmallow.readthedocs.io
155
+
156
+ .. |pypi-package| image:: https://badgen.net/pypi/v/flask-marshmallow
157
+ :target: https://pypi.org/project/flask-marshmallow/
158
+ :alt: Latest version
159
+
160
+ .. |build-status| image:: https://github.com/marshmallow-code/flask-marshmallow/actions/workflows/build-release.yml/badge.svg
161
+ :target: https://github.com/marshmallow-code/flask-marshmallow/actions/workflows/build-release.yml
162
+ :alt: Build status
163
+
164
+ .. |docs| image:: https://readthedocs.org/projects/flask-marshmallow/badge/
165
+ :target: https://flask-marshmallow.readthedocs.io/
166
+ :alt: Documentation
167
+
168
+ .. |marshmallow3| image:: https://badgen.net/badge/marshmallow/3
169
+ :target: https://marshmallow.readthedocs.io/en/latest/upgrading.html
170
+ :alt: marshmallow 3 compatible
171
+
@@ -2,7 +2,7 @@
2
2
  Flask-Marshmallow
3
3
  *****************
4
4
 
5
- |pypi-package| |build-status| |docs| |marshmallow23| |black|
5
+ |pypi-package| |build-status| |docs| |marshmallow3|
6
6
 
7
7
  Flask + marshmallow for beautiful APIs
8
8
  ======================================
@@ -103,7 +103,7 @@ Project Links
103
103
 
104
104
  - Docs: https://flask-marshmallow.readthedocs.io/
105
105
  - Changelog: http://flask-marshmallow.readthedocs.io/en/latest/changelog.html
106
- - PyPI: https://pypi.python.org/pypi/flask-marshmallow
106
+ - PyPI: https://pypi.org/project/flask-marshmallow/
107
107
  - Issues: https://github.com/marshmallow-code/flask-marshmallow/issues
108
108
 
109
109
  License
@@ -118,15 +118,15 @@ MIT licensed. See the bundled `LICENSE <https://github.com/marshmallow-code/flas
118
118
  .. |pypi-package| image:: https://badgen.net/pypi/v/flask-marshmallow
119
119
  :target: https://pypi.org/project/flask-marshmallow/
120
120
  :alt: Latest version
121
- .. |build-status| image:: https://dev.azure.com/sloria/sloria/_apis/build/status/marshmallow-code.flask-marshmallow?branchName=dev
122
- :target: https://dev.azure.com/sloria/sloria/_build/latest?definitionId=14&branchName=dev
121
+
122
+ .. |build-status| image:: https://github.com/marshmallow-code/flask-marshmallow/actions/workflows/build-release.yml/badge.svg
123
+ :target: https://github.com/marshmallow-code/flask-marshmallow/actions/workflows/build-release.yml
123
124
  :alt: Build status
125
+
124
126
  .. |docs| image:: https://readthedocs.org/projects/flask-marshmallow/badge/
125
127
  :target: https://flask-marshmallow.readthedocs.io/
126
128
  :alt: Documentation
127
- .. |marshmallow23| image:: https://badgen.net/badge/marshmallow/2,3?list=1
129
+
130
+ .. |marshmallow3| image:: https://badgen.net/badge/marshmallow/3
128
131
  :target: https://marshmallow.readthedocs.io/en/latest/upgrading.html
129
132
  :alt: marshmallow 3 compatible
130
- .. |black| image:: https://badgen.net/badge/code%20style/black/000
131
- :target: https://github.com/ambv/black
132
- :alt: code style: black
@@ -14,7 +14,7 @@ Flask + marshmallow for beautiful APIs
14
14
 
15
15
  <h3>Useful Links</h3>
16
16
  <ul>
17
- <li><a href="http://pypi.python.org/pypi/flask-marshmallow">Flask-Marshmallow @ PyPI</a></li>
17
+ <li><a href="https://pypi.org/project/flask-marshmallow/">Flask-Marshmallow @ PyPI</a></li>
18
18
  <li><a href="http://github.com/marshmallow-code/flask-marshmallow">Flask-Marshmallow @ GitHub</a></li>
19
19
  <li><a href="http://github.com/marshmallow-code/flask-marshmallow/issues">Issue Tracker</a></li>
20
20
  </ul>
@@ -18,7 +18,7 @@ Flask + marshmallow for beautiful APIs
18
18
 
19
19
  <h3>Useful Links</h3>
20
20
  <ul>
21
- <li><a href="http://pypi.python.org/pypi/flask-marshmallow">Flask-Marshmallow @ PyPI</a></li>
21
+ <li><a href="https://pypi.org/project/flask-marshmallow/">Flask-Marshmallow @ PyPI</a></li>
22
22
  <li><a href="http://github.com/marshmallow-code/flask-marshmallow">Flask-Marshmallow @ GitHub</a></li>
23
23
  <li><a href="http://github.com/marshmallow-code/flask-marshmallow/issues">Issue Tracker</a></li>
24
24
  </ul>
@@ -1,10 +1,7 @@
1
- # -*- coding: utf-8 -*-
2
1
  import datetime as dt
3
- import sys
2
+ import importlib.metadata
4
3
  import os
5
-
6
- sys.path.insert(0, os.path.abspath(os.path.join("..", "src")))
7
- import flask_marshmallow # noqa: E402
4
+ import sys
8
5
 
9
6
  sys.path.append(os.path.abspath("_themes"))
10
7
  extensions = ["sphinx.ext.autodoc", "sphinx.ext.intersphinx", "sphinx_issues"]
@@ -34,13 +31,13 @@ source_suffix = ".rst"
34
31
  master_doc = "index"
35
32
 
36
33
  # General information about the project.
37
- project = u"Flask-Marshmallow"
38
- copyright = u"2014-{:%Y}".format(
34
+ project = "Flask-Marshmallow"
35
+ copyright = "2014-{:%Y}".format(
39
36
  dt.datetime.utcfromtimestamp(os.path.getmtime("../CHANGELOG.rst"))
40
37
  )
41
38
 
42
39
 
43
- version = release = flask_marshmallow.__version__
40
+ version = release = importlib.metadata.version("flask-marshmallow")
44
41
  exclude_patterns = ["_build"]
45
42
  # The name of the Pygments (syntax highlighting) style to use.
46
43
  pygments_style = "flask_theme_support.FlaskyStyle"
@@ -4,7 +4,7 @@ Flask-Marshmallow: Flask + marshmallow for beautiful APIs
4
4
 
5
5
  :ref:`changelog <changelog>` //
6
6
  `github <http://github.com/marshmallow-code/flask-marshmallow>`_ //
7
- `pypi <http://pypi.python.org/pypi/flask-marshmallow>`_ //
7
+ `pypi <https://pypi.org/project/flask-marshmallow/>`_ //
8
8
  `issues <http://github.com/marshmallow-code/flask-marshmallow/issues>`_
9
9
 
10
10
 
@@ -178,6 +178,7 @@ You can now use your schema to dump and load your ORM objects.
178
178
 
179
179
  - By default, `~flask_marshmallow.sqla.SQLAlchemySchema` uses the scoped session created by Flask-SQLAlchemy.
180
180
  - `~flask_marshmallow.sqla.SQLAlchemySchema` subclasses `flask_marshmallow.Schema`, so it includes the `~flask_marshmallow.Schema.jsonify` method.
181
+
181
182
  Note: By default, Flask's `jsonify` method sorts the list of keys and returns consistent results to ensure that external HTTP caches aren't trashed. As a side effect, this will override `ordered=True <https://marshmallow.readthedocs.io/en/latest/quickstart.html#ordering-output>`_
182
183
  in the SQLAlchemySchema's `class Meta` (if you set it). To disable this, set `JSON_SORT_KEYS=False` in your Flask app config. In production it's recommended to let `jsonify` sort the keys and not set `ordered=True` in your `~flask_marshmallow.sqla.SQLAlchemySchema` in order to minimize generation time and maximize cacheability of the results.
183
184
 
@@ -228,6 +229,9 @@ API
228
229
  .. automodule:: flask_marshmallow.fields
229
230
  :members:
230
231
 
232
+ .. automodule:: flask_marshmallow.validate
233
+ :members:
234
+
231
235
  .. automodule:: flask_marshmallow.sqla
232
236
  :members:
233
237
 
@@ -0,0 +1,66 @@
1
+ [project]
2
+ name = "flask-marshmallow"
3
+ version = "1.0.0"
4
+ description = "Flask + marshmallow for beautiful APIs"
5
+ readme = "README.rst"
6
+ license = { file = "LICENSE" }
7
+ maintainers = [{ name = "Steven Loria", email = "sloria1@gmail.com" }]
8
+ classifiers = [
9
+ "Environment :: Web Environment",
10
+ "Intended Audience :: Developers",
11
+ "License :: OSI Approved :: MIT License",
12
+ "Natural Language :: English",
13
+ "Programming Language :: Python :: 3",
14
+ "Programming Language :: Python :: 3.8",
15
+ "Programming Language :: Python :: 3.9",
16
+ "Programming Language :: Python :: 3.10",
17
+ "Programming Language :: Python :: 3.11",
18
+ "Programming Language :: Python :: 3.12",
19
+ "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
20
+ ]
21
+ requires-python = ">=3.8"
22
+ dependencies = ["Flask", "marshmallow>=3.0.0", "packaging>=17.0"]
23
+
24
+ [project.urls]
25
+ Issues = "https://github.com/marshmallow-code/flask-marshmallow/issues"
26
+ Funding = "https://opencollective.com/marshmallow"
27
+
28
+ [project.optional-dependencies]
29
+ docs = [
30
+ "marshmallow-sqlalchemy>=0.19.0",
31
+ "Sphinx==7.2.6",
32
+ "sphinx-issues==3.0.1",
33
+ ]
34
+ tests = ["flask-marshmallow[sqlalchemy]", "pytest"]
35
+ dev = ["flask-marshmallow[tests]", "tox", "pre-commit~=3.5"]
36
+ sqlalchemy = ["flask-sqlalchemy>=3.0.0", "marshmallow-sqlalchemy>=0.29.0"]
37
+
38
+ [build-system]
39
+ requires = ["flit_core<4"]
40
+ build-backend = "flit_core.buildapi"
41
+
42
+ [tool.flit.sdist]
43
+ include = ["docs/", "tests/", "CHANGELOG.rst", "CONTRIBUTING.rst", "tox.ini"]
44
+ exclude = ["docs/_build/"]
45
+
46
+ [tool.ruff]
47
+ src = ["src"]
48
+ fix = true
49
+ show-fixes = true
50
+ show-source = true
51
+
52
+ [tool.ruff.lint]
53
+ select = [
54
+ "B", # flake8-bugbear
55
+ "E", # pycodestyle error
56
+ "F", # pyflakes
57
+ "I", # isort
58
+ "UP", # pyupgrade
59
+ "W", # pycodestyle warning
60
+ ]
61
+
62
+ [tool.pytest.ini_options]
63
+ filterwarnings = [
64
+ "error",
65
+ "ignore:distutils Version classes are deprecated\\. Use packaging.version instead\\.:DeprecationWarning:marshmallow",
66
+ ]
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  """
3
2
  flask_marshmallow
4
3
  ~~~~~~~~~~~~~~~~~
@@ -7,9 +6,9 @@
7
6
  with your Flask application.
8
7
  """
9
8
  import warnings
10
- from distutils.version import LooseVersion
11
9
 
12
- from marshmallow import fields as base_fields, exceptions, pprint
10
+ from marshmallow import exceptions, pprint
11
+ from marshmallow import fields as base_fields
13
12
 
14
13
  from . import fields
15
14
  from .schema import Schema
@@ -25,14 +24,20 @@ else:
25
24
  except ImportError:
26
25
  warnings.warn(
27
26
  "Flask-SQLAlchemy integration requires "
28
- "marshmallow-sqlalchemy to be installed."
27
+ "marshmallow-sqlalchemy to be installed.",
28
+ stacklevel=2,
29
29
  )
30
30
  else:
31
31
  has_sqla = True
32
32
 
33
- __version__ = "0.14.0"
34
- __version_info__ = tuple(LooseVersion(__version__).version)
35
- __all__ = ["EXTENSION_NAME", "Marshmallow", "Schema", "fields", "exceptions", "pprint"]
33
+ __all__ = [
34
+ "EXTENSION_NAME",
35
+ "Marshmallow",
36
+ "Schema",
37
+ "fields",
38
+ "exceptions",
39
+ "pprint",
40
+ ]
36
41
 
37
42
  EXTENSION_NAME = "flask-marshmallow"
38
43
 
@@ -48,7 +53,7 @@ def _attach_fields(obj):
48
53
  setattr(obj, attr, getattr(fields, attr))
49
54
 
50
55
 
51
- class Marshmallow(object):
56
+ class Marshmallow:
52
57
  """Wrapper class that integrates Marshmallow with a Flask application.
53
58
 
54
59
  To use it, instantiate with an application::
@@ -76,14 +81,15 @@ class Marshmallow(object):
76
81
  })
77
82
 
78
83
 
79
- In order to integrate with Flask-SQLAlchemy, this extension must be initialized *after*
80
- `flask_sqlalchemy.SQLAlchemy`. ::
84
+ In order to integrate with Flask-SQLAlchemy, this extension must be initialized
85
+ *after* `flask_sqlalchemy.SQLAlchemy`. ::
81
86
 
82
87
  db = SQLAlchemy(app)
83
88
  ma = Marshmallow(app)
84
89
 
85
- This gives you access to `ma.SQLAlchemySchema` and `ma.SQLAlchemyAutoSchema`, which generate
86
- marshmallow `~marshmallow.Schema` classes based on the passed in model or table. ::
90
+ This gives you access to `ma.SQLAlchemySchema` and `ma.SQLAlchemyAutoSchema`, which
91
+ generate marshmallow `~marshmallow.Schema` classes
92
+ based on the passed in model or table. ::
87
93
 
88
94
  class AuthorSchema(ma.SQLAlchemyAutoSchema):
89
95
  class Meta:
@@ -112,7 +118,7 @@ class Marshmallow(object):
112
118
 
113
119
  # If using Flask-SQLAlchemy, attach db.session to SQLAlchemySchema
114
120
  if has_sqla and "sqlalchemy" in app.extensions:
115
- db = app.extensions["sqlalchemy"].db
121
+ db = app.extensions["sqlalchemy"]
116
122
  if self.SQLAlchemySchema:
117
123
  self.SQLAlchemySchema.OPTIONS_CLASS.session = db.session
118
124
  if self.SQLAlchemyAutoSchema:
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  """
3
2
  flask_marshmallow.fields
4
3
  ~~~~~~~~~~~~~~~~~~~~~~~~
@@ -10,12 +9,18 @@
10
9
  """
11
10
  import re
12
11
 
13
- from flask import url_for
14
- from marshmallow import fields
15
- from marshmallow import missing
12
+ from flask import current_app, url_for
13
+ from marshmallow import fields, missing
16
14
 
17
-
18
- __all__ = ["URLFor", "UrlFor", "AbsoluteURLFor", "AbsoluteUrlFor", "Hyperlinks"]
15
+ __all__ = [
16
+ "URLFor",
17
+ "UrlFor",
18
+ "AbsoluteURLFor",
19
+ "AbsoluteUrlFor",
20
+ "Hyperlinks",
21
+ "File",
22
+ "Config",
23
+ ]
19
24
 
20
25
 
21
26
  _tpl_pattern = re.compile(r"\s*<\s*(\S*)\s*>\s*")
@@ -70,7 +75,10 @@ class URLFor(fields.Field):
70
75
  Usage: ::
71
76
 
72
77
  url = URLFor('author_get', values=dict(id='<id>'))
73
- https_url = URLFor('author_get', values=dict(id='<id>', _scheme='https', _external=True))
78
+ https_url = URLFor(
79
+ 'author_get',
80
+ values=dict(id='<id>', _scheme='https', _external=True),
81
+ )
74
82
 
75
83
  :param str endpoint: Flask endpoint name.
76
84
  :param dict values: Same keyword arguments as Flask's url_for, except string
@@ -81,9 +89,9 @@ class URLFor(fields.Field):
81
89
 
82
90
  _CHECK_ATTRIBUTE = False
83
91
 
84
- def __init__(self, endpoint, values=None, **kwargs):
92
+ def __init__(self, endpoint, values=None, id=None, **kwargs):
85
93
  self.endpoint = endpoint
86
- self.values = values or kwargs # kwargs for backward compatibility
94
+ self.values = values or {}
87
95
  fields.Field.__init__(self, **kwargs)
88
96
 
89
97
  def _serialize(self, value, key, obj):
@@ -101,8 +109,7 @@ class URLFor(fields.Field):
101
109
  param_values[name] = attribute_value
102
110
  else:
103
111
  raise AttributeError(
104
- "{attr_name!r} is not a valid "
105
- "attribute of {obj!r}".format(attr_name=attr_name, obj=obj)
112
+ f"{attr_name!r} is not a valid " f"attribute of {obj!r}"
106
113
  )
107
114
  else:
108
115
  param_values[name] = attr_tpl
@@ -116,10 +123,10 @@ class AbsoluteURLFor(URLFor):
116
123
  """Field that outputs the absolute URL for an endpoint."""
117
124
 
118
125
  def __init__(self, endpoint, values=None, **kwargs):
119
- if values: # for backward compatibility
126
+ if values:
120
127
  values["_external"] = True
121
128
  else:
122
- kwargs["_external"] = True
129
+ values = {"_external": True}
123
130
  URLFor.__init__(self, endpoint=endpoint, values=values, **kwargs)
124
131
 
125
132
 
@@ -127,7 +134,9 @@ AbsoluteUrlFor = AbsoluteURLFor
127
134
 
128
135
 
129
136
  def _rapply(d, func, *args, **kwargs):
130
- """Apply a function to all values in a dictionary or list of dictionaries, recursively."""
137
+ """Apply a function to all values in a dictionary or
138
+ list of dictionaries, recursively.
139
+ """
131
140
  if isinstance(d, (tuple, list)):
132
141
  return [_rapply(each, func, *args, **kwargs) for each in d]
133
142
  if isinstance(d, dict):
@@ -179,3 +188,60 @@ class Hyperlinks(fields.Field):
179
188
 
180
189
  def _serialize(self, value, attr, obj):
181
190
  return _rapply(self.schema, _url_val, key=attr, obj=obj)
191
+
192
+
193
+ class File(fields.Field):
194
+ """A binary file field for uploaded files.
195
+
196
+ Examples: ::
197
+
198
+ class ImageSchema(Schema):
199
+ image = File(required=True)
200
+ """
201
+
202
+ def __init__(self, *args, **kwargs):
203
+ super().__init__(*args, **kwargs)
204
+ # Metadata used by apispec
205
+ self.metadata["type"] = "string"
206
+ self.metadata["format"] = "binary"
207
+
208
+ default_error_messages = {"invalid": "Not a valid file."}
209
+
210
+ def _deserialize(self, value, attr, data, **kwargs):
211
+ from werkzeug.datastructures import FileStorage
212
+
213
+ if not isinstance(value, FileStorage):
214
+ raise self.make_error("invalid")
215
+ return value
216
+
217
+
218
+ class Config(fields.Field):
219
+ """A field for Flask configuration values.
220
+
221
+ Examples: ::
222
+
223
+ from flask import Flask
224
+
225
+ app = Flask(__name__)
226
+ app.config['API_TITLE'] = 'Pet API'
227
+
228
+ class FooSchema(Schema):
229
+ user = String()
230
+ title = Config('API_TITLE')
231
+
232
+ This field should only be used in an output schema. A ``ValueError`` will
233
+ be raised if the config key is not found in the app config.
234
+
235
+ :param str key: The key of the configuration value.
236
+ """
237
+
238
+ _CHECK_ATTRIBUTE = False
239
+
240
+ def __init__(self, key: str, **kwargs):
241
+ fields.Field.__init__(self, **kwargs)
242
+ self.key = key
243
+
244
+ def _serialize(self, value, attr, obj, **kwargs):
245
+ if self.key not in current_app.config:
246
+ raise ValueError(f"The key {self.key!r} is not found in the app config.")
247
+ return current_app.config[self.key]
@@ -1,9 +1,6 @@
1
- # -*- coding: utf-8 -*-
2
1
  import flask
3
2
  import marshmallow as ma
4
3
 
5
- from flask_marshmallow.compat import _MARSHMALLOW_VERSION_INFO
6
-
7
4
  sentinel = object()
8
5
 
9
6
 
@@ -35,8 +32,5 @@ class Schema(ma.Schema):
35
32
  """
36
33
  if many is sentinel:
37
34
  many = self.many
38
- if _MARSHMALLOW_VERSION_INFO[0] >= 3:
39
- data = self.dump(obj, many=many)
40
- else:
41
- data = self.dump(obj, many=many).data
35
+ data = self.dump(obj, many=many)
42
36
  return flask.jsonify(data, *args, **kwargs)