Skip to content

Commit

Permalink
Merge pull request #253 from sirosen/catch-warnings-in-tests
Browse files Browse the repository at this point in the history
Catch warnings in tests & remove support for older URLFor argument syntax
  • Loading branch information
sirosen committed Feb 6, 2023
2 parents bec7f93 + a3a970f commit 3faf8c4
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 55 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ Changelog

* Only support Python>=3.6, marshmallow>=3.0.0, and marshmallow-sqlalchemy>=0.24.0.
* Add support for python3.11
* *Backwards-incompatible*: ``URLFor`` and ``AbsoluteURLFor`` now do not accept
parameters for ``flask.url_for`` as top-level parameters. They must always be
passed in the ``values`` dictionary, as explained in the v0.14.0 changelog.

Bug fixes:

* Address distutils deprecation warning in Python 3.10 (:pr:`242`).
Thanks :user:`GabrielLins64` for the PR.

0.14.0 (2020-09-27)
*******************
Expand Down
9 changes: 9 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,12 @@ ignore = E203, E266, E501, W503, B907
max-line-length = 110
max-complexity = 18
select = B,C,E,F,W,T4,B9

[tool:pytest]
filterwarnings =
# warnings are errors
error
# marshmallow-sqlalchemy triggers this on sqlalchemy 2.0
ignore:The Query\.get\(\) method is considered legacy:sqlalchemy.exc.LegacyAPIWarning
# marshmallow triggers this when we test on marshmallow version 3.0
ignore:distutils Version classes are deprecated\. Use packaging.version instead\.:DeprecationWarning:marshmallow
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
EXTRAS_REQUIRE["tests"] = EXTRAS_REQUIRE["sqlalchemy"] + ["pytest", "mock"]
EXTRAS_REQUIRE["dev"] = EXTRAS_REQUIRE["tests"] + EXTRAS_REQUIRE["lint"] + ["tox"]

REQUIRES = ["Flask", "marshmallow>=3.0.0"]
REQUIRES = ["Flask", "marshmallow>=3.0.0", "packaging>=17.0"]


def find_version(fname):
Expand Down
4 changes: 2 additions & 2 deletions src/flask_marshmallow/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
with your Flask application.
"""
import warnings
from distutils.version import LooseVersion
from packaging.version import Version

from marshmallow import fields as base_fields, exceptions, pprint

Expand All @@ -30,7 +30,7 @@
has_sqla = True

__version__ = "0.14.0"
__version_info__ = tuple(LooseVersion(__version__).version)
__version_info__ = Version(__version__).release
__all__ = ["EXTENSION_NAME", "Marshmallow", "Schema", "fields", "exceptions", "pprint"]

EXTENSION_NAME = "flask-marshmallow"
Expand Down
8 changes: 4 additions & 4 deletions src/flask_marshmallow/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ class URLFor(fields.Field):

_CHECK_ATTRIBUTE = False

def __init__(self, endpoint, values=None, **kwargs):
def __init__(self, endpoint, values=None, id=None, **kwargs):
self.endpoint = endpoint
self.values = values or kwargs # kwargs for backward compatibility
self.values = values or {}
fields.Field.__init__(self, **kwargs)

def _serialize(self, value, key, obj):
Expand Down Expand Up @@ -115,10 +115,10 @@ class AbsoluteURLFor(URLFor):
"""Field that outputs the absolute URL for an endpoint."""

def __init__(self, endpoint, values=None, **kwargs):
if values: # for backward compatibility
if values:
values["_external"] = True
else:
kwargs["_external"] = True
values = {"_external": True}
URLFor.__init__(self, endpoint=endpoint, values=values, **kwargs)


Expand Down
16 changes: 11 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Pytest fixtures for the test suite."""
import pytest
from flask import Flask
from flask_marshmallow import Marshmallow
import pytest

_app = Flask(__name__)
_app.testing = True
Expand Down Expand Up @@ -64,7 +64,7 @@ def book(id):
return "Legend of Bagger Vance"


@pytest.yield_fixture(scope="function")
@pytest.fixture(scope="function")
def app():
ctx = _app.test_request_context()
ctx.push()
Expand All @@ -85,10 +85,13 @@ class AuthorSchema(ma.Schema):
class Meta:
fields = ("id", "name", "absolute_url", "links")

absolute_url = ma.AbsoluteURLFor("author", id="<id>")
absolute_url = ma.AbsoluteURLFor("author", values={"id": "<id>"})

links = ma.Hyperlinks(
{"self": ma.URLFor("author", id="<id>"), "collection": ma.URLFor("authors")}
{
"self": ma.URLFor("author", values={"id": "<id>"}),
"collection": ma.URLFor("authors"),
}
)

class BookSchema(ma.Schema):
Expand All @@ -98,7 +101,10 @@ class Meta:
author = ma.Nested(AuthorSchema)

links = ma.Hyperlinks(
{"self": ma.URLFor("book", id="<id>"), "collection": ma.URLFor("books")}
{
"self": ma.URLFor("book", values={"id": "<id>"}),
"collection": ma.URLFor("books"),
}
)

# So we can access schemas.AuthorSchema, etc.
Expand Down
6 changes: 3 additions & 3 deletions tests/markers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import pytest
import flask
from distutils.version import LooseVersion
from packaging.version import Version


flask_version = LooseVersion(flask.__version__)
flask_version = Version(flask.__version__)
flask_1_req = pytest.mark.skipif(
flask_version < LooseVersion("0.11"), reason="flask 0.11 or higher required"
flask_version < Version("0.11"), reason="flask 0.11 or higher required"
)
50 changes: 15 additions & 35 deletions tests/test_fields.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from flask import url_for
from werkzeug.routing import BuildError
import pytest
from flask import url_for
from flask_marshmallow.fields import _tpl
from werkzeug.routing import BuildError


@pytest.mark.parametrize(
Expand All @@ -14,10 +14,6 @@ def test_tpl(template):


def test_url_field(ma, mockauthor):
field = ma.URLFor("author", id="<id>")
result = field.serialize("url", mockauthor)
assert result == url_for("author", id=mockauthor.id)

field = ma.URLFor("author", values=dict(id="<id>"))
result = field.serialize("url", mockauthor)
assert result == url_for("author", id=mockauthor.id)
Expand All @@ -28,13 +24,6 @@ def test_url_field(ma, mockauthor):


def test_url_field_with_invalid_attribute(ma, mockauthor):
field = ma.URLFor("author", id="<not-an-attr>")
expected_msg = "{!r} is not a valid attribute of {!r}".format(
"not-an-attr", mockauthor
)
with pytest.raises(AttributeError, match=expected_msg):
field.serialize("url", mockauthor)

field = ma.URLFor("author", values=dict(id="<not-an-attr>"))
expected_msg = "{!r} is not a valid attribute of {!r}".format(
"not-an-attr", mockauthor
Expand All @@ -44,10 +33,6 @@ def test_url_field_with_invalid_attribute(ma, mockauthor):


def test_url_field_handles_nested_attribute(ma, mockbook, mockauthor):
field = ma.URLFor("author", id="<author.id>")
result = field.serialize("url", mockbook)
assert result == url_for("author", id=mockauthor.id)

field = ma.URLFor("author", values=dict(id="<author.id>"))
result = field.serialize("url", mockbook)
assert result == url_for("author", id=mockauthor.id)
Expand All @@ -56,14 +41,6 @@ def test_url_field_handles_nested_attribute(ma, mockbook, mockauthor):
def test_url_field_handles_none_attribute(ma, mockbook, mockauthor):
mockbook.author = None

field = ma.URLFor("author", id="<author>")
result = field.serialize("url", mockbook)
assert result is None

field = ma.URLFor("author", id="<author.id>")
result = field.serialize("url", mockbook)
assert result is None

field = ma.URLFor("author", values=dict(id="<author>"))
result = field.serialize("url", mockbook)
assert result is None
Expand All @@ -74,11 +51,6 @@ def test_url_field_handles_none_attribute(ma, mockbook, mockauthor):


def test_url_field_deserialization(ma):
field = ma.URLFor("author", id="<not-an-attr>", allow_none=True)
# noop
assert field.deserialize("foo") == "foo"
assert field.deserialize(None) is None

field = ma.URLFor("author", values=dict(id="<not-an-attr>"), allow_none=True)
# noop
assert field.deserialize("foo") == "foo"
Expand All @@ -93,7 +65,10 @@ def test_invalid_endpoint_raises_build_error(ma, mockauthor):

def test_hyperlinks_field(ma, mockauthor):
field = ma.Hyperlinks(
{"self": ma.URLFor("author", id="<id>"), "collection": ma.URLFor("authors")}
{
"self": ma.URLFor("author", values={"id": "<id>"}),
"collection": ma.URLFor("authors"),
}
)

result = field.serialize("_links", mockauthor)
Expand All @@ -106,7 +81,10 @@ def test_hyperlinks_field(ma, mockauthor):
def test_hyperlinks_field_recurses(ma, mockauthor):
field = ma.Hyperlinks(
{
"self": {"href": ma.URLFor("author", id="<id>"), "title": "The author"},
"self": {
"href": ma.URLFor("author", values={"id": "<id>"}),
"title": "The author",
},
"collection": {"href": ma.URLFor("authors"), "title": "Authors list"},
}
)
Expand All @@ -121,7 +99,7 @@ def test_hyperlinks_field_recurses(ma, mockauthor):
def test_hyperlinks_field_recurses_into_list(ma, mockauthor):
field = ma.Hyperlinks(
[
{"rel": "self", "href": ma.URLFor("author", id="<id>")},
{"rel": "self", "href": ma.URLFor("author", values={"id": "<id>"})},
{"rel": "collection", "href": ma.URLFor("authors")},
]
)
Expand All @@ -134,7 +112,9 @@ def test_hyperlinks_field_recurses_into_list(ma, mockauthor):


def test_hyperlinks_field_deserialization(ma):
field = ma.Hyperlinks({"href": ma.URLFor("author", id="<id>")}, allow_none=True)
field = ma.Hyperlinks(
{"href": ma.URLFor("author", values={"id": "<id>"})}, allow_none=True
)
# noop
assert field.deserialize("/author") == "/author"
assert field.deserialize(None) is None
Expand All @@ -153,7 +133,7 @@ def test_absolute_url_deserialization(ma):


def test_aliases(ma):
from flask_marshmallow.fields import UrlFor, AbsoluteUrlFor, URLFor, AbsoluteURLFor
from flask_marshmallow.fields import AbsoluteUrlFor, AbsoluteURLFor, UrlFor, URLFor

assert UrlFor is URLFor
assert AbsoluteUrlFor is AbsoluteURLFor
10 changes: 5 additions & 5 deletions tests/test_sqla.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@


class TestSQLAlchemy:
@pytest.yield_fixture()
@pytest.fixture
def extapp(self):
app_ = Flask("extapp")
app_.testing = True
Expand All @@ -46,15 +46,15 @@ def book(id):

ctx.pop()

@pytest.fixture()
@pytest.fixture
def db(self, extapp):
return extapp.extensions["sqlalchemy"].db
return extapp.extensions["sqlalchemy"]

@pytest.fixture()
@pytest.fixture
def extma(self, extapp):
return extapp.extensions["flask-marshmallow"]

@pytest.yield_fixture()
@pytest.fixture
def models(self, db):
class AuthorModel(db.Model):
__tablename__ = "author"
Expand Down

0 comments on commit 3faf8c4

Please sign in to comment.