Skip to content

Commit

Permalink
build(python): add support for Python 3.13 (#732)
Browse files Browse the repository at this point in the history
  • Loading branch information
jlemesh committed Oct 10, 2024
1 parent 79d0483 commit 80d88dc
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 6 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-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4

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 @@ -17,6 +16,7 @@

import requests
from bravado.exception import HTTPError
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_regular_path, is_uuid_v4
Expand Down Expand Up @@ -500,9 +500,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 @@ -93,6 +93,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
)
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ envlist =
py310
py311
py312
py313

[testenv]
deps =
Expand Down

0 comments on commit 80d88dc

Please sign in to comment.