Skip to content

Commit

Permalink
build(python): add support for Python 3.13 (#736)
Browse files Browse the repository at this point in the history
  • Loading branch information
jlemesh authored and mdonadoni committed Nov 26, 2024
1 parent c822dd6 commit fd9b944
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ jobs:
strategy:
matrix:
testenv: [lowest, release]
python: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12']
python: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v3

Expand Down
8 changes: 4 additions & 4 deletions reana_client/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
# under the terms of the MIT License; see LICENSE file for more details.
"""REANA REST API client."""

import cgi
import json
import logging
import os
Expand All @@ -27,6 +26,7 @@
from reana_commons.errors import REANASecretAlreadyExists, REANASecretDoesNotExist
from werkzeug.local import LocalProxy

from reana_client.api.utils import get_content_disposition_filename
from reana_client.config import ERROR_MESSAGES
from reana_client.errors import FileDeletionError, FileUploadError
from reana_client.utils import is_uuid_v4, is_regular_path
Expand Down Expand Up @@ -492,9 +492,9 @@ def download_file(workflow, file_name, access_token):
verify=False,
)
if "Content-Disposition" in http_response.headers:
content_disposition = http_response.headers.get("Content-Disposition")
value, params = cgi.parse_header(content_disposition)
file_name = params.get("filename", "downloaded_file")
file_name = get_content_disposition_filename(
http_response.headers.get("Content-Disposition")
)

# A zip archive is downloaded if multiple files are requested
multiple_files_zipped = (
Expand Down
18 changes: 17 additions & 1 deletion reana_client/api/utils.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# -*- coding: utf-8 -*-
#
# This file is part of REANA.
# Copyright (C) 2019, 2020, 2021 CERN.
# Copyright (C) 2019, 2020, 2021, 2024 CERN.
#
# REANA is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.
"""REANA client API utils."""

from email.message import Message


def get_path_from_operation_id(paths_dict, operation_id):
"""Find API path based on operation id."""
Expand All @@ -17,3 +19,17 @@ def get_path_from_operation_id(paths_dict, operation_id):
if paths_dict[path][method]["operationId"] == operation_id:
return path
return None


def get_content_disposition_filename(content_disposition_header):
"""Retrieve filename from a Content-Disposition like header.
Using email module instead of cgi.parse header due to https://peps.python.org/pep-0594/#cgi
Return a filename if found, otherwise a default string.
"""
msg = Message()
msg["content-disposition"] = content_disposition_header
filename = msg.get_filename()

return filename if filename else "downloaded_file"
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python",
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
Expand Down
33 changes: 33 additions & 0 deletions tests/test_api_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
#
# This file is part of REANA.
# Copyright (C) 2024 CERN.
#
# REANA is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""REANA API utils tests."""

import pytest

from reana_client.api.utils import get_content_disposition_filename


@pytest.mark.parametrize(
"content_disposition_header, expected_filename",
[
("inline", "downloaded_file"),
("attachment", "downloaded_file"),
('attachment; filename="example.txt"', "example.txt"),
("attachment; filename*=UTF-8''example.txt", "example.txt"),
("attachment; filename=folder", "folder"),
('attachment; filename="folder/*/example.txt"', "folder/*/example.txt"),
],
)
def test_get_content_disposition_filename(
content_disposition_header, expected_filename
):
assert (
get_content_disposition_filename(content_disposition_header)
== expected_filename
)
10 changes: 9 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@
# under the terms of the MIT License; see LICENSE file for more details.

[tox]
envlist = py36, py37, py38, py39, py310, py311, py312
envlist =
py36
py37
py38
py39
py310
py311
py312
py313

[testenv]
deps = pytest
Expand Down

0 comments on commit fd9b944

Please sign in to comment.