Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@
Changelog
=========

spyne-2.15.0
------------
* Python 3.11, 3.12, 3.13 and 3.14 support.
* Fixed ``SyntaxWarning`` for invalid string escapes in ``protocol/http.py``,
``protocol/json.py`` and ``util/invregexp.py``.
* Fixed ``SyntaxWarning`` from PEP 765 (Python 3.14): ``break`` statement
hoisted out of a ``finally`` block in ``protocol/cloth/to_cloth.py``.
* ``server/twisted/http.py``: ``cgi`` module was removed in Python 3.13;
the multipart code path now falls back to the ``legacy-cgi`` PyPI package
and raises a descriptive error if it is needed but missing.
* Replaced deprecated ``unittest`` aliases (``assertEquals`` etc.) in the
test suite for Python 3.12+ compatibility.

spyne-2.14.0
------------
* Python 3.10 support.
Expand Down
4 changes: 4 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ def run_tests(self):
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
'Programming Language :: Python :: 3.14',
'Programming Language :: Python :: Implementation :: CPython',
#'Programming Language :: Python :: Implementation :: Jython',
'Programming Language :: Python :: Implementation :: PyPy',
Expand Down
2 changes: 1 addition & 1 deletion spyne/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
class LogicError(Exception):
pass

__version__ = '2.15.0-alpha'
__version__ = '2.15.0'

from pytz import utc as LOCAL_TZ
from decimal import Decimal as D
Expand Down
7 changes: 3 additions & 4 deletions spyne/protocol/cloth/to_cloth.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,10 +764,9 @@ def complex_to_cloth(self, ctx, cls, inst, cloth, parent, name=None,
ret.throw(e)
except StopIteration:
pass
finally:
# cf below
if not (as_attr or as_data):
break
# cf below; hoisted out of finally for PEP 765 (Py 3.14)
if not (as_attr or as_data):
break
else:
# this is here so that attribute on complex model doesn't get
# mixed with in-line attr inside complex model. if an element
Expand Down
2 changes: 1 addition & 1 deletion spyne/protocol/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ def _compile_host_pattern(cls, pattern):
pattern = _full_pattern_re.sub(r'(?P<\1>.*)', pattern)

pattern_b = pattern.encode(cls.HOST_ENCODING)
pattern_b = _fragment_pattern_b_re.sub(b'(?P<\\1>[^\.]*)', pattern_b)
pattern_b = _fragment_pattern_b_re.sub(rb'(?P<\1>[^\.]*)', pattern_b)
pattern_b = _full_pattern_b_re.sub(b'(?P<\\1>.*)', pattern_b)

return re.compile(pattern), re.compile(pattern_b)
Expand Down
2 changes: 1 addition & 1 deletion spyne/protocol/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
#

"""The ``spyne.protocol.json`` package contains the Json-related protocols.
r"""The ``spyne.protocol.json`` package contains the Json-related protocols.
Currently, only :class:`spyne.protocol.json.JsonDocument` is supported.

Initially released in 2.8.0-rc.
Expand Down
13 changes: 12 additions & 1 deletion spyne/server/twisted/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,13 @@
logger = logging.getLogger(__name__)

import re
import cgi
try:
import cgi # removed in Python 3.13; pip install legacy-cgi to restore
except ImportError: # pragma: no cover
try:
import legacy_cgi as cgi
except ImportError:
cgi = None
import gzip
import shutil
import threading
Expand Down Expand Up @@ -485,6 +491,11 @@ def _get_file_info(ctx):
shutil.copyfileobj(ifstr, content)
content.seek(0)

if cgi is None:
raise RuntimeError(
"Multipart parsing requires the 'cgi' module which was removed in "
"Python 3.13. Install 'legacy-cgi' (pip install legacy-cgi) to "
"enable this code path.")
img = cgi.FieldStorage(
fp=content,
headers=ctx.in_header_doc,
Expand Down
4 changes: 2 additions & 2 deletions spyne/test/interop/test_django.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,13 @@ class DjangoServiceTestCase(TestCase):
def test_handle_does_not_exist(self):
"""Test if Django service handles `ObjectDoesNotExist` exceptions."""
client = DjangoTestClient('/api/', app)
with self.assertRaisesRegexp(Fault, 'Client.FieldContainerNotFound'):
with self.assertRaisesRegex(Fault, 'Client.FieldContainerNotFound'):
client.service.raise_does_not_exist()

def test_handle_validation_error(self):
"""Test if Django service handles `ValidationError` exceptions."""
client = DjangoTestClient('/api/', app)
with self.assertRaisesRegexp(Fault, 'Client.ValidationError'):
with self.assertRaisesRegex(Fault, 'Client.ValidationError'):
client.service.raise_validation_error()


Expand Down
6 changes: 3 additions & 3 deletions spyne/test/multipython/model/test_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class Attributes(ComplexModel.Attributes):

Base2 = Base.customize(prop1=4)

self.assertNotEquals(Base.Attributes.prop1, Base2.Attributes.prop1)
self.assertNotEqual(Base.Attributes.prop1, Base2.Attributes.prop1)
self.assertEqual(Base.Attributes.prop2, Base2.Attributes.prop2)

class Derived(Base):
Expand All @@ -156,15 +156,15 @@ class Attributes(Base.Attributes):
self.assertEqual(Derived.Attributes.prop1, 3)
self.assertEqual(Derived2.Attributes.prop1, 5)

self.assertNotEquals(Derived.Attributes.prop3, Derived2.Attributes.prop3)
self.assertNotEqual(Derived.Attributes.prop3, Derived2.Attributes.prop3)
self.assertEqual(Derived.Attributes.prop4, Derived2.Attributes.prop4)

Derived3 = Derived.customize(prop3=12)
Base.prop1 = 4

# changes made to bases propagate, unless overridden
self.assertEqual(Derived.Attributes.prop1, Base.Attributes.prop1)
self.assertNotEquals(Derived2.Attributes.prop1, Base.Attributes.prop1)
self.assertNotEqual(Derived2.Attributes.prop1, Base.Attributes.prop1)
self.assertEqual(Derived3.Attributes.prop1, Base.Attributes.prop1)

def test_declare_order(self):
Expand Down
4 changes: 2 additions & 2 deletions spyne/test/protocol/_test_dictdoc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,7 @@ def some_call(p):
print(ctx.out_document)

d = convert_dict({"some_callResponse": {"some_callResult": inner}})
self.assertEquals(ctx.out_document[0], d)
self.assertEqual(ctx.out_document[0], d)

def test_validation_freq_parent(self):
class C(ComplexModel):
Expand Down Expand Up @@ -1308,7 +1308,7 @@ def some_call(sc):
doc = [{"C": {"s1": "s1","s2": "s2"}}]
ctx = _dry_me([SomeService], {"some_call": doc})

self.assertEquals(ctx.out_document[0], convert_dict(
self.assertEqual(ctx.out_document[0], convert_dict(
{'some_callResponse': {'some_callResult': {'C': {'s2': 's2'}}}})
)

Expand Down
2 changes: 1 addition & 1 deletion spyne/util/invregexp.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ def count(gen):


def invregexp(regex):
"""Call this routine as a generator to return all the strings that
r"""Call this routine as a generator to return all the strings that
match the input regular expression.
for s in invregexp("[A-Z]{3}\d{3}"):
print s
Expand Down