[packages/python-flask-restful] - new, with dozen of patches to make it compatible with recent python 3/flask 3

qboosh qboosh at pld-linux.org
Thu Dec 25 20:23:03 CET 2025


commit 07408285ee9e6644637eac91bd022ec36f76793a
Author: Jakub Bogusz <qboosh at pld-linux.org>
Date:   Thu Dec 25 20:22:40 2025 +0100

    - new, with dozen of patches to make it compatible with recent python 3/flask 3

 Flask-RESTful-encoding.patch      |   7 ++
 Flask-RESTful-flask-app.patch     |  31 +++++++
 Flask-RESTful-flask.patch         |  15 ++++
 Flask-RESTful-mock.patch          |  27 ++++++
 Flask-RESTful-pynose.patch        |  20 +++++
 Flask-RESTful-pytz.patch          |  49 +++++++++++
 Flask-RESTful-werkzeug-json.patch |  63 ++++++++++++++
 python-flask-restful.spec         | 177 ++++++++++++++++++++++++++++++++++++++
 8 files changed, 389 insertions(+)
---
diff --git a/python-flask-restful.spec b/python-flask-restful.spec
new file mode 100644
index 0000000..952d731
--- /dev/null
+++ b/python-flask-restful.spec
@@ -0,0 +1,177 @@
+#
+# Conditional build:
+%bcond_with	doc	# Sphinx documentation (_themes dir is missing in sdist)
+%bcond_without	tests	# unit tests
+%bcond_without	python2 # CPython 2.x module
+%bcond_without	python3 # CPython 3.x module
+
+Summary:	Simple framework for creating REST APIs
+Summary(pl.UTF-8):	Prosty szkielet do tworzenia API REST-owych
+Name:		python-flask-restful
+Version:	0.3.10
+Release:	1
+License:	BSD
+Group:		Libraries/Python
+#Source0Download: https://pypi.org/simple/flask-restful/
+Source0:	https://files.pythonhosted.org/packages/source/F/Flask-RESTful/Flask-RESTful-%{version}.tar.gz
+# Source0-md5:	2a1f17e91c526a03bf721e178d8fce94
+Patch0:		Flask-RESTful-encoding.patch
+Patch1:		Flask-RESTful-pytz.patch
+Patch2:		Flask-RESTful-mock.patch
+Patch3:		Flask-RESTful-flask.patch
+Patch4:		Flask-RESTful-pynose.patch
+# https://github.com/flask-restful/flask-restful/pull/983
+Patch5:		Flask-RESTful-werkzeug-json.patch
+# https://github.com/flask-restful/flask-restful/pull/972
+Patch6:		Flask-RESTful-flask-app.patch
+URL:		https://pypi.org/project/Flask-RESTful/
+%if %{with python2}
+BuildRequires:	python-modules >= 1:2.7
+BuildRequires:	python-setuptools
+%if %{with tests}
+BuildRequires:	python-aniso8601 >= 0.82
+BuildRequires:	python-blinker
+BuildRequires:	python-flask >= 0.8
+BuildRequires:	python-mock >= 0.8
+BuildRequires:	python-nose >= 1.1.2
+BuildRequires:	python-pytz
+BuildRequires:	python-six >= 1.3.0
+%endif
+%endif
+%if %{with python3}
+BuildRequires:	python3-modules >= 1:3.4
+BuildRequires:	python3-setuptools
+%if %{with tests}
+BuildRequires:	python3-aniso8601 >= 0.82
+BuildRequires:	python3-blinker
+BuildRequires:	python3-flask >= 0.8
+BuildRequires:	python3-pynose >= 1.1.2
+BuildRequires:	python3-pytz
+BuildRequires:	python3-six >= 1.3.0
+%endif
+%endif
+BuildRequires:	rpm-pythonprov
+BuildRequires:	rpmbuild(macros) >= 1.714
+%if %{with doc}
+BuildRequires:	sphinx-pdg-3
+%endif
+Requires:	python-modules >= 1:2.7
+BuildArch:	noarch
+BuildRoot:	%{tmpdir}/%{name}-%{version}-root-%(id -u -n)
+
+%description
+Flask-RESTful provides the building blocks for creating a great REST
+API.
+
+%description -l pl.UTF-8
+Flask-RESTful dostarcza elementy do budowania dobrych API REST-owych.
+
+%package -n python3-flask-restful
+Summary:	Simple framework for creating REST APIs
+Summary(pl.UTF-8):	Prosty szkielet do tworzenia API REST-owych
+Group:		Libraries/Python
+Requires:	python3-modules >= 1:3.4
+
+%description -n python3-flask-restful
+Flask-RESTful provides the building blocks for creating a great REST
+API.
+
+%description -n python3-flask-restful -l pl.UTF-8
+Flask-RESTful dostarcza elementy do budowania dobrych API REST-owych.
+
+%package apidocs
+Summary:	API documentation for Python flask_restful module
+Summary(pl.UTF-8):	Dokumentacja API modułu Pythona flask_restful
+Group:		Documentation
+
+%description apidocs
+API documentation for Python flask_restful module.
+
+%description apidocs -l pl.UTF-8
+Dokumentacja API modułu Pythona flask_restful.
+
+%prep
+%setup -q -n Flask-RESTful-%{version}
+%patch -P0 -p1
+%patch -P1 -p1
+%patch -P2 -p1
+%patch -P3 -p1
+%patch -P4 -p1
+%patch -P5 -p1
+%patch -P6 -p1
+
+%build
+%if %{with python2}
+%py_build
+
+%if %{with tests}
+# test_api uses types.SimpleNamespace added in Python 3.3
+PYTHONPATH=$(pwd) \
+nosetests-%{py_ver} -w tests --ignore-files test_api.py
+%endif
+%endif
+
+%if %{with python3}
+%py3_build
+
+%if %{with tests}
+# some tests fail (not ready for Flask 3 yet)
+PYTHONPATH=$(pwd) \
+nosetests-%{py3_ver} -w tests \
+	-e test_exception_header_forwarded \
+	-e test_media_types_method \
+	-e test_media_types_q \
+	-e test_redirect
+%endif
+%endif
+
+%if %{with doc}
+%{__make} -C docs html \
+	SPHINXBUILD=sphinx-build-3
+%endif
+
+%install
+rm -rf $RPM_BUILD_ROOT
+
+%if %{with python2}
+%py_install
+
+%py_postclean
+
+install -d $RPM_BUILD_ROOT%{_examplesdir}/python-flask-restful-%{version}
+cp -p examples/*.py $RPM_BUILD_ROOT%{_examplesdir}/python-flask-restful-%{version}
+%endif
+
+%if %{with python3}
+%py3_install
+
+install -d $RPM_BUILD_ROOT%{_examplesdir}/python3-flask-restful-%{version}
+cp -p examples/*.py $RPM_BUILD_ROOT%{_examplesdir}/python3-flask-restful-%{version}
+%endif
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%if %{with python2}
+%files
+%defattr(644,root,root,755)
+%doc AUTHORS.md LICENSE README.md
+%{py_sitescriptdir}/flask_restful
+%{py_sitescriptdir}/Flask_RESTful-%{version}-py*.egg-info
+%{_examplesdir}/python-flask-restful-%{version}
+%endif
+
+%if %{with python3}
+%files -n python3-flask-restful
+%defattr(644,root,root,755)
+%doc AUTHORS.md LICENSE README.md
+%{py3_sitescriptdir}/flask_restful
+%{py3_sitescriptdir}/Flask_RESTful-%{version}-py*.egg-info
+%{_examplesdir}/python3-flask-restful-%{version}
+%endif
+
+%if %{with doc}
+%files apidocs
+%defattr(644,root,root,755)
+%doc docs/_build/html/*
+%endif
diff --git a/Flask-RESTful-encoding.patch b/Flask-RESTful-encoding.patch
new file mode 100644
index 0000000..4ea5fa1
--- /dev/null
+++ b/Flask-RESTful-encoding.patch
@@ -0,0 +1,7 @@
+--- Flask-RESTful-0.3.10/flask_restful/__init__.py.orig	2023-05-21 05:45:44.000000000 +0200
++++ Flask-RESTful-0.3.10/flask_restful/__init__.py	2025-12-21 10:28:00.938410239 +0100
+@@ -1,3 +1,4 @@
++# -*- coding: utf-8 -*-
+ from __future__ import absolute_import
+ from functools import wraps, partial
+ from flask import request, url_for, current_app
diff --git a/Flask-RESTful-flask-app.patch b/Flask-RESTful-flask-app.patch
new file mode 100644
index 0000000..370e3e6
--- /dev/null
+++ b/Flask-RESTful-flask-app.patch
@@ -0,0 +1,31 @@
+From 923c3938ed9ba6eb81bd8b2b966fd64ae988a042 Mon Sep 17 00:00:00 2001
+From: menglutao <azraeltml at gmail.com>
+Date: Wed, 27 Dec 2023 13:48:19 +0100
+Subject: [PATCH] Set self.app in init_app
+
+---
+ flask_restful/__init__.py | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/flask_restful/__init__.py b/flask_restful/__init__.py
+index 46915c8b..9d64dc86 100644
+--- a/flask_restful/__init__.py
++++ b/flask_restful/__init__.py
+@@ -118,8 +118,7 @@ def __init__(self, app=None, prefix='',
+         self.app = None
+         self.blueprint = None
+ 
+-        if app is not None:
+-            self.app = app
++        if app is not None:          
+             self.init_app(app)
+ 
+     def init_app(self, app):
+@@ -137,6 +136,7 @@ def init_app(self, app):
+             api.init_app(app)
+ 
+         """
++        self.app = app  # Set the app here
+         # If app is a blueprint, defer the initialization
+         try:
+             app.record(self._deferred_blueprint_init)
diff --git a/Flask-RESTful-flask.patch b/Flask-RESTful-flask.patch
new file mode 100644
index 0000000..1a0cf3f
--- /dev/null
+++ b/Flask-RESTful-flask.patch
@@ -0,0 +1,15 @@
+--- Flask-RESTful-0.3.10/tests/test_api.py.orig	2023-05-21 05:51:10.000000000 +0200
++++ Flask-RESTful-0.3.10/tests/test_api.py	2025-12-23 06:19:38.900011643 +0100
+@@ -1,7 +1,11 @@
+ import unittest
+ import json
+ from flask import Flask, Blueprint, redirect, views, abort as flask_abort
+-from flask.signals import got_request_exception, signals_available
++from flask.signals import got_request_exception
++try:
++    from flask.signals import signals_available
++except ImportError:
++    signals_available = True  # Flask>=2.3.0
+ try:
+     from mock import Mock
+ except:
diff --git a/Flask-RESTful-mock.patch b/Flask-RESTful-mock.patch
new file mode 100644
index 0000000..aaecf76
--- /dev/null
+++ b/Flask-RESTful-mock.patch
@@ -0,0 +1,27 @@
+--- Flask-RESTful-0.3.10/tests/test_fields.py.orig	2025-12-22 05:35:25.708779441 +0100
++++ Flask-RESTful-0.3.10/tests/test_fields.py	2025-12-22 05:37:46.711348897 +0100
+@@ -2,7 +2,10 @@ from decimal import Decimal
+ from functools import partial
+ import pytz
+ import unittest
+-from mock import Mock
++try:
++    from mock import Mock
++except ImportError:
++    from unittest.mock import Mock
+ from flask_restful.fields import MarshallingException
+ from flask_restful.utils import OrderedDict
+ from flask_restful import fields
+--- Flask-RESTful-0.3.10/tests/test_reqparse.py.orig	2021-05-17 21:16:30.000000000 +0200
++++ Flask-RESTful-0.3.10/tests/test_reqparse.py	2025-12-22 05:38:12.091211403 +0100
+@@ -1,6 +1,9 @@
+ # -*- coding: utf-8 -*-
+ import unittest
+-from mock import Mock, patch
++try:
++    from mock import Mock, patch
++except ImportError:
++    from unittest.mock import Mock, patch
+ from flask import Flask
+ from werkzeug import exceptions
+ from werkzeug.wrappers import Request
diff --git a/Flask-RESTful-pynose.patch b/Flask-RESTful-pynose.patch
new file mode 100644
index 0000000..c15292a
--- /dev/null
+++ b/Flask-RESTful-pynose.patch
@@ -0,0 +1,20 @@
+pynose doesn't define PEP8'd assert_snake_case variants of TestCase.assertCamelCases in nose.tools
+--- Flask-RESTful-0.3.10/tests/test_fields.py.orig	2025-12-23 06:12:25.239117653 +0100
++++ Flask-RESTful-0.3.10/tests/test_fields.py	2025-12-23 06:27:01.096706053 +0100
+@@ -12,7 +12,15 @@ from flask_restful import fields
+ from datetime import datetime, timedelta, tzinfo
+ from flask import Flask, Blueprint
+ #noinspection PyUnresolvedReferences
+-from nose.tools import assert_equals  # you need it for tests in form of continuations
++try:
++    from nose.tools import assert_equals  # you need it for tests in form of continuations
++except ImportError:
++    class _FakeCase(unittest.TestCase):
++        def nop():
++            pass
++    _t = _FakeCase("nop")
++    def assert_equals(a, b):
++        return _t.assertEqual(a, b)
+ 
+ 
+ class Foo(object):
diff --git a/Flask-RESTful-pytz.patch b/Flask-RESTful-pytz.patch
new file mode 100644
index 0000000..3e1a5bb
--- /dev/null
+++ b/Flask-RESTful-pytz.patch
@@ -0,0 +1,49 @@
+pytz objects are not fully compatible with tzinfo datetime field, use localize() to get
+correct results with recent pytz/tzdata releases (after extending supported dates,
+the default tz offset is lunar time based).
+Due to wrong usage, two test cases expected result were wrong (assuming +0100 for CET,
+like in the beginning of the year, not +0200, taking DST in account on given date).
+--- Flask-RESTful-0.3.10/tests/test_fields.py.orig	2021-05-17 21:16:30.000000000 +0200
++++ Flask-RESTful-0.3.10/tests/test_fields.py	2025-12-21 17:54:34.773255578 +0100
+@@ -55,7 +55,7 @@ def test_rfc822_datetime_formatters():
+          "Sat, 01 Jan 2011 23:59:59 -0000"),
+         (datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.utc),
+          "Sat, 01 Jan 2011 23:59:59 -0000"),
+-        (datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.timezone('CET')),
++        (pytz.timezone('CET').localize(datetime(2011, 1, 1, 23, 59, 59)),
+          "Sat, 01 Jan 2011 22:59:59 -0000")
+     ]
+     for date_obj, expected in dates:
+@@ -73,7 +73,7 @@ def test_iso8601_datetime_formatters():
+          "2011-01-01T23:59:59+00:00"),
+         (datetime(2011, 1, 1, 23, 59, 59, 1000, tzinfo=pytz.utc),
+          "2011-01-01T23:59:59.001000+00:00"),
+-        (datetime(2011, 1, 1, 23, 59, 59, tzinfo=pytz.timezone('CET')),
++        (pytz.timezone('CET').localize(datetime(2011, 1, 1, 23, 59, 59)),
+          "2011-01-01T23:59:59+01:00")
+     ]
+     for date_obj, expected in dates:
+@@ -364,9 +364,9 @@ class FieldsTestCase(unittest.TestCase):
+         self.assertEqual("Mon, 22 Aug 2011 20:58:45 -0000", field.output("bar", obj))
+ 
+     def test_rfc822_date_field_with_offset(self):
+-        obj = {"bar": datetime(2011, 8, 22, 20, 58, 45, tzinfo=pytz.timezone('CET'))}
++        obj = {"bar": pytz.timezone('CET').localize(datetime(2011, 8, 22, 20, 58, 45))}
+         field = fields.DateTime()
+-        self.assertEqual("Mon, 22 Aug 2011 19:58:45 -0000", field.output("bar", obj))
++        self.assertEqual("Mon, 22 Aug 2011 18:58:45 -0000", field.output("bar", obj))
+ 
+     def test_iso8601_date_field_without_offset(self):
+         obj = {"bar": datetime(2011, 8, 22, 20, 58, 45)}
+@@ -374,9 +374,9 @@ class FieldsTestCase(unittest.TestCase):
+         self.assertEqual("2011-08-22T20:58:45", field.output("bar", obj))
+ 
+     def test_iso8601_date_field_with_offset(self):
+-        obj = {"bar": datetime(2011, 8, 22, 20, 58, 45, tzinfo=pytz.timezone('CET'))}
++        obj = {"bar": pytz.timezone('CET').localize(datetime(2011, 8, 22, 20, 58, 45))}
+         field = fields.DateTime(dt_format='iso8601')
+-        self.assertEqual("2011-08-22T20:58:45+01:00", field.output("bar", obj))
++        self.assertEqual("2011-08-22T20:58:45+02:00", field.output("bar", obj))
+ 
+     def test_unsupported_datetime_format(self):
+         obj = {"bar": datetime(2011, 8, 22, 20, 58, 45)}
diff --git a/Flask-RESTful-werkzeug-json.patch b/Flask-RESTful-werkzeug-json.patch
new file mode 100644
index 0000000..3052199
--- /dev/null
+++ b/Flask-RESTful-werkzeug-json.patch
@@ -0,0 +1,63 @@
+From 51a6373d95918bd55bfede7918a2b71d28a32ee2 Mon Sep 17 00:00:00 2001
+From: Mark Wine <marcoxwine at gmail.com>
+Date: Wed, 5 Jun 2024 21:27:32 -0700
+Subject: [PATCH] remove json parsing if content type is not application/json
+
+---
+ flask_restful/reqparse.py |  8 +++++++-
+ tests/test_reqparse.py    | 16 ++++++++++++++++
+ 2 files changed, 23 insertions(+), 1 deletion(-)
+
+diff --git a/flask_restful/reqparse.py b/flask_restful/reqparse.py
+index 9bb30991..121c7be6 100644
+--- a/flask_restful/reqparse.py
++++ b/flask_restful/reqparse.py
+@@ -113,6 +113,12 @@ def source(self, request):
+         """Pulls values off the request in the provided location
+         :param request: The flask request object to parse arguments from
+         """
++        location = self.location
++        if getattr(request, "content_type", "") != "application/json":
++            if self.location == "json":
++                return MultiDict()
++            elif "json" in self.location:
++                location = tuple(loc for loc in self.location if loc != 'json')
+         if isinstance(self.location, six.string_types):
+             value = getattr(request, self.location, MultiDict())
+             if callable(value):
+@@ -121,7 +127,7 @@ def source(self, request):
+                 return value
+         else:
+             values = MultiDict()
+-            for l in self.location:
++            for l in location:
+                 value = getattr(request, l, None)
+                 if callable(value):
+                     value = value()
+diff --git a/tests/test_reqparse.py b/tests/test_reqparse.py
+index 1d75e404..762cff59 100644
+--- a/tests/test_reqparse.py
++++ b/tests/test_reqparse.py
+@@ -811,6 +811,22 @@ def test_not_json_location_and_content_type_json(self):
+                                       content_type='application/json'):
+             parser.parse_args()  # Should not raise a 400: BadRequest
+ 
++    def test_content_type_not_json(self):
++        app = Flask(__name__)
++
++        parser = RequestParser()
++        parser.add_argument("foo")
++
++        with app.test_request_context("/bubble", method="get", data=json.dumps({"foo": "bar"})):
++            args = parser.parse_args()
++            self.assertIsNone(args.get("foo"))
++
++        with app.test_request_context("/bubble", method="get",
++                                      content_type="application/json",
++                                      data=json.dumps({"foo": "bar"})):
++            args = parser.parse_args()
++            self.assertEqual(args["foo"], "bar")
++
+     def test_request_parser_remove_argument(self):
+         req = Request.from_values("/bubble?foo=baz")
+         parser = RequestParser()
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/python-flask-restful.git/commitdiff/07408285ee9e6644637eac91bd022ec36f76793a



More information about the pld-cvs-commit mailing list