Skip to content

Commit

Permalink
[DEV-12949] Python 3.13 Compatibility (#349)
Browse files Browse the repository at this point in the history
* Fix unconditional import missed by reduce base install size PR

* Replace `cgi.parse_header()` with `email.message.EmailMessage`

This makes `indico-client` compatible with Python 3.13, which removed
the deprecated `cgi` module.

https://docs.python.org/3/whatsnew/3.13.html#pep-594-remove-dead-batteries-from-the-standard-library

* Update readme and tox with supported Python versions
  • Loading branch information
mawelborn authored Jan 29, 2025
1 parent 54fccb6 commit 049d802
Show file tree
Hide file tree
Showing 4 changed files with 11 additions and 8 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

---

Required: Python 3.6, 3.7, or 3.8
Required: Python 3.9+

From PyPI:

Expand Down
13 changes: 8 additions & 5 deletions indico/http/serialization.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
"""
Handles deserialization / decoding of responses
"""
import cgi
import gzip
import io
import json
import logging
import traceback
from collections import defaultdict

import msgpack
from email.message import EmailMessage

from indico.errors import IndicoDecodingError

Expand All @@ -23,7 +21,7 @@ def decompress(response):


def deserialize(response, force_json=False, force_decompress=False):
content_type, params = cgi.parse_header(response.headers.get("Content-Type"))
content_type, params = parse_header(response.headers.get("Content-Type"))

if force_decompress or content_type in ["application/x-gzip", "application/gzip"]:
content = decompress(response)
Expand All @@ -45,7 +43,7 @@ def deserialize(response, force_json=False, force_decompress=False):
)

async def aio_deserialize(response, force_json=False, force_decompress=False):
content_type, params = cgi.parse_header(response.headers.get("Content-Type"))
content_type, params = parse_header(response.headers.get("Content-Type"))
content = await response.read()

if force_decompress or content_type in ["application/x-gzip", "application/gzip"]:
Expand All @@ -65,6 +63,11 @@ async def aio_deserialize(response, force_json=False, force_decompress=False):
content_type, charset, content.decode("ascii", "ignore")
)

def parse_header(header: str) -> tuple[str, dict[str, str]]:
email = EmailMessage()
email["Content-Type"] = header
return email.get_content_type(), email["Content-Type"].params

def raw_bytes(content, *args, **kwargs):
return content

Expand Down
2 changes: 1 addition & 1 deletion tox.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -yqq apt-tr
#deadsnakes holds old versions of python for ubuntu
RUN DEBIAN_FRONTEND=noninteractive apt-get install -yqq software-properties-common && add-apt-repository ppa:deadsnakes/ppa

RUN DEBIAN_FRONTEND=noninteractive apt-get -yqq install python3.7 python3.8 python3.9 python3.10 python3.11 python3.12 python3-pip
RUN DEBIAN_FRONTEND=noninteractive apt-get -yqq install python3.9 python3.10 python3.11 python3.12 python3.13 python3-pip

RUN pip3 install tox==4.11.3

Expand Down
2 changes: 1 addition & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# content of: tox.ini , put in same dir as setup.py
[tox]
envlist = py38,py39,py310,py311,py312
envlist = py39,py310,py311,py312,py313

[testenv]
extras = all
Expand Down

0 comments on commit 049d802

Please sign in to comment.