Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Python3.13 #1469

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: ["3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12", "3.13"]

steps:
- name: Checkout code
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pypi-release-aboutcode-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.12
python-version: 3.13

- name: Install flot
run: python -m pip install flot --user
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pypi-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.12
python-version: 3.13

- name: Install pypa/build
run: python -m pip install build --user
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ v34.9.3 (unreleased)
* Add SCANCODEIO_RQ_REDIS_SSL setting to enable SSL.
https://github.com/aboutcode-org/scancode.io/issues/1465

- Add support for Python 3.13.

v34.9.2 (2024-12-10)
--------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ Pre-installation Checklist

Before you install ScanCode.io, make sure you have the following prerequisites:

* **Python: versions 3.10 to 3.12** found at https://www.python.org/downloads/
* **Python: versions 3.10 to 3.13** found at https://www.python.org/downloads/
* **Git**: most recent release available at https://git-scm.com/
* **PostgreSQL**: release 11 or later found at https://www.postgresql.org/ or
https://postgresapp.com/ on macOS
Expand Down
10 changes: 9 additions & 1 deletion scanpipe/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# ScanCode.io is a free software code scanning tool from nexB Inc. and others.
# Visit https://github.com/aboutcode-org/scancode.io for support and download.

import importlib.util
import inspect
import logging
import sys
Expand Down Expand Up @@ -134,7 +135,14 @@ def register_pipeline_from_file(self, path):
after being found.
"""
module_name = inspect.getmodulename(path)
module = SourceFileLoader(module_name, str(path)).load_module()

loader = SourceFileLoader(module_name, str(path))
spec = importlib.util.spec_from_loader(module_name, loader)
if spec and spec.loader:
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
else:
raise ImportError(f"Could not load module from path: {path}")

def is_local_module_pipeline(obj):
return is_pipeline(obj) and obj.__module__ == module_name
Expand Down
4 changes: 2 additions & 2 deletions scanpipe/pipes/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
# ScanCode.io is a free software code scanning tool from nexB Inc. and others.
# Visit https://github.com/aboutcode-org/scancode.io for support and download.

import cgi
import json
import logging
import os
Expand All @@ -33,6 +32,7 @@
from urllib.parse import urlparse

from django.conf import settings
from django.utils.http import parse_header_parameters

import git
import requests
Expand Down Expand Up @@ -113,7 +113,7 @@ def fetch_http(uri, to=None):
raise requests.RequestException

content_disposition = response.headers.get("content-disposition", "")
_, params = cgi.parse_header(content_disposition)
_, params = parse_header_parameters(content_disposition)
filename = params.get("filename")
if not filename:
# Using `response.url` in place of provided `Scan.uri` since the former
Expand Down
3 changes: 2 additions & 1 deletion scanpipe/pipes/spdx.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from dataclasses import dataclass
from dataclasses import field
from datetime import datetime
from datetime import timezone
from pathlib import Path
from typing import List # Python 3.8 compatibility

Expand Down Expand Up @@ -125,7 +126,7 @@ class CreationInfo:
Format: YYYY-MM-DDThh:mm:ssZ
"""
created: str = field(
default_factory=lambda: datetime.utcnow().isoformat(timespec="seconds") + "Z",
default_factory=lambda: datetime.now(timezone.utc).isoformat(timespec="seconds")
)

def as_dict(self):
Expand Down
20 changes: 20 additions & 0 deletions scanpipe/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@

import os
import uuid
import warnings
from datetime import datetime
from functools import wraps
from unittest import mock

from django.apps import apps
Expand All @@ -47,6 +49,24 @@
mocked_now = mock.Mock(now=lambda: datetime(2010, 10, 10, 10, 10, 10))


def filter_warnings(action, category, module=None):
"""Apply a warning filter to a function."""

def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
original_filters = warnings.filters[:]
try:
warnings.filterwarnings(action, category=category, module=module)
return func(*args, **kwargs)
finally:
warnings.filters = original_filters

return wrapper

return decorator


def make_project(name=None, **extra):
name = name or str(uuid.uuid4())[:8]
return Project.objects.create(name=name, **extra)
Expand Down
3 changes: 3 additions & 0 deletions scanpipe/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from scanpipe.pipes.input import copy_input
from scanpipe.pipes.output import JSONResultsGenerator
from scanpipe.tests import dependency_data1
from scanpipe.tests import filter_warnings
from scanpipe.tests import make_package
from scanpipe.tests import make_project
from scanpipe.tests import make_resource_file
Expand Down Expand Up @@ -460,6 +461,7 @@ def test_scanpipe_api_project_create_multiple_pipelines(self):
}
self.assertEqual(expected, response.data)

@filter_warnings("ignore", category=DeprecationWarning, module="scanpipe")
def test_scanpipe_api_project_create_pipeline_old_name_compatibility(self):
data = {
"name": "Single string",
Expand Down Expand Up @@ -940,6 +942,7 @@ def test_scanpipe_api_project_action_add_pipeline(self, mock_execute_pipeline_ta
self.assertEqual({"status": "Pipeline added."}, response.data)
mock_execute_pipeline_task.assert_called_once()

@filter_warnings("ignore", category=DeprecationWarning, module="scanpipe")
def test_scanpipe_api_project_action_add_pipeline_old_name_compatibility(self):
url = reverse("project-add-pipeline", args=[self.project1.uuid])
data = {
Expand Down
2 changes: 2 additions & 0 deletions scanpipe/tests/test_apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

from scanpipe.models import Project
from scanpipe.models import Run
from scanpipe.tests import filter_warnings
from scanpipe.tests import license_policies_index
from scanpipe.tests.pipelines.register_from_file import RegisterFromFile

Expand Down Expand Up @@ -124,6 +125,7 @@ def test_scanpipe_apps_get_pipeline_choices(self):
self.assertIn(main_pipeline, choices)
self.assertNotIn(addon_pipeline, choices)

@filter_warnings("ignore", category=DeprecationWarning, module="scanpipe")
def test_scanpipe_apps_get_new_pipeline_name(self):
self.assertEqual(
"scan_codebase", scanpipe_app.get_new_pipeline_name("scan_codebase")
Expand Down
3 changes: 3 additions & 0 deletions scanpipe/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
from scanpipe.models import Run
from scanpipe.models import WebhookSubscription
from scanpipe.pipes import purldb
from scanpipe.tests import filter_warnings
from scanpipe.tests import make_package
from scanpipe.tests import make_resource_file

Expand Down Expand Up @@ -264,6 +265,7 @@ def test_scanpipe_management_command_add_input_copy_codebase(self):
expected, sorted([path.name for path in project.codebase_path.iterdir()])
)

@filter_warnings("ignore", category=DeprecationWarning, module="scanpipe")
def test_scanpipe_management_command_add_pipeline(self):
out = StringIO()

Expand Down Expand Up @@ -1043,6 +1045,7 @@ def test_scanpipe_management_command_mixin_create_project_notes(self):
)
self.assertEqual(notes, project.notes)

@filter_warnings("ignore", category=DeprecationWarning, module="scanpipe")
def test_scanpipe_management_command_mixin_create_project_pipelines(self):
expected = "non-existing is not a valid pipeline"
with self.assertRaisesMessage(CommandError, expected):
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ classifiers =
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: 3.12
Programming Language :: Python :: 3.13
Topic :: Utilities
keywords =
open source
Expand Down
Loading