Skip to content

Commit ce4cae0

Browse files
authored
Upgrade Django to version 5.0.0 #1020 (#1021)
* Upgrade multiple dependencies to latest version #1020 Signed-off-by: tdruez <[email protected]> * Upgrade Django to version 5.0.0 #1020 Signed-off-by: tdruez <[email protected]> * Upgrade the virtualenv package #1020 Signed-off-by: tdruez <[email protected]> * Fix some DeprecationWarning #1020 Signed-off-by: tdruez <[email protected]> * Remove support for Python 3.8 and 3.9 #1020 Signed-off-by: tdruez <[email protected]> * Migrate to POST-only logout view #1020 Signed-off-by: tdruez <[email protected]> * Silent the warning about DB access during app initialization #1020 Signed-off-by: tdruez <[email protected]> * Fix failing test #1020 Signed-off-by: tdruez <[email protected]> * Add changelog entry #1020 Signed-off-by: tdruez <[email protected]> * Fix the python_inspector import reference #1020 Signed-off-by: tdruez <[email protected]> * Improve unit test support across OSes #1020 Signed-off-by: tdruez <[email protected]> --------- Signed-off-by: tdruez <[email protected]>
1 parent e7cfcda commit ce4cae0

19 files changed

+84
-76
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
strategy:
3232
max-parallel: 4
3333
matrix:
34-
python-version: ["3.8", "3.9", "3.10", "3.11"]
34+
python-version: ["3.10", "3.11"]
3535

3636
steps:
3737
- name: Checkout code

CHANGELOG.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
Changelog
22
=========
33

4-
v32.8.0 (unreleased)
4+
v33.0.0 (unreleased)
55
--------------------
66

7+
- Upgrade Django to version 5.0 and drop support for Python 3.8 and 3.9
8+
https://github.com/nexB/scancode.io/issues/1020
9+
710
- Refactor run_scancode to not fail on scan errors happening at the resource level,
811
such as a timeout. Project error message are created instead.
912
https://github.com/nexB/scancode.io/issues/1018

docs/custom-pipelines.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ the entry point to the pipeline under the ``[options.entry_points]`` section.
240240
packages=find:
241241
include_package_data = true
242242
zip_safe = false
243-
python_requires = >=3.8
243+
python_requires = >=3.10
244244
setup_requires = setuptools_scm[toml] >= 4
245245
246246
[options.packages.find]

docs/installation.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ Pre-installation Checklist
224224

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

227-
* **Python: versions 3.8 to 3.11** found at https://www.python.org/downloads/
227+
* **Python: versions 3.10 to 3.11** found at https://www.python.org/downloads/
228228
* **Git**: most recent release available at https://git-scm.com/
229229
* **PostgreSQL**: release 11 or later found at https://www.postgresql.org/ or
230230
https://postgresapp.com/ on macOS

etc/thirdparty/virtualenv.pyz

13.7 KB
Binary file not shown.

etc/thirdparty/virtualenv.pyz.ABOUT

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
about_resource: virtualenv.pyz
22
name: get-virtualenv
3-
version: 20.24.6
4-
download_url: https://github.com/pypa/get-virtualenv/raw/20.24.6/public/virtualenv.pyz
3+
version: 20.25.0
4+
download_url: https://github.com/pypa/get-virtualenv/raw/20.25.0/public/virtualenv.pyz
55
description: virtualenv is a tool to create isolated Python environments.
66
homepage_url: https://github.com/pypa/virtualenv
77
license_expression: lgpl-2.1-plus AND (bsd-new OR apache-2.0) AND mit AND python AND bsd-new
@@ -10,4 +10,4 @@ copyright: Copyright (c) The Python Software Foundation and others
1010
redistribute: yes
1111
attribute: yes
1212
track_changes: yes
13-
package_url: pkg:github/pypa/get-virtualenv@20.24.6#public/virtualenv.pyz
13+
package_url: pkg:github/pypa/get-virtualenv@20.25.0#public/virtualenv.pyz

scanpipe/apps.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import inspect
2424
import logging
2525
import sys
26+
import warnings
2627
from importlib.machinery import SourceFileLoader
2728
from pathlib import Path
2829

@@ -74,6 +75,12 @@ def ready(self):
7475
# before its running process death.
7576
# In ASYNC mode, the cleanup is handled by the "ScanCodeIOWorker" worker.
7677
if not settings.SCANCODEIO_ASYNC and "runserver" in sys.argv:
78+
warnings.filterwarnings(
79+
"ignore",
80+
message="Accessing the database during app initialization",
81+
category=RuntimeWarning,
82+
module="django",
83+
)
7784
self.sync_runs_and_jobs()
7885

7986
def load_pipelines(self):
@@ -82,9 +89,7 @@ def load_pipelines(self):
8289
pipelines Python files found at `SCANCODEIO_PIPELINES_DIRS` locations.
8390
"""
8491
entry_points = importlib_metadata.entry_points()
85-
86-
# Ignore duplicated entries caused by duplicated paths in `sys.path`.
87-
pipeline_entry_points = set(entry_points.get("scancodeio_pipelines"))
92+
pipeline_entry_points = set(entry_points.select(group="scancodeio_pipelines"))
8893

8994
for entry_point in sorted(pipeline_entry_points):
9095
self.register_pipeline(name=entry_point.name, cls=entry_point.load())

scanpipe/pipes/__init__.py

-13
Original file line numberDiff line numberDiff line change
@@ -302,19 +302,6 @@ def get_bin_executable(filename):
302302
return str(Path(sys.executable).parent / filename)
303303

304304

305-
def remove_prefix(text, prefix):
306-
"""
307-
Remove the `prefix` from `text`.
308-
Note that build-in `removeprefix` was added in Python3.9 but we need to keep
309-
this one for Python3.8 support.
310-
https://docs.python.org/3.9/library/stdtypes.html#str.removeprefix
311-
"""
312-
if text.startswith(prefix):
313-
prefix_len = len(prefix)
314-
return text[prefix_len:]
315-
return text
316-
317-
318305
class LoopProgress:
319306
"""
320307
A context manager for logging progress in loops.

scanpipe/pipes/d2d.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1402,7 +1402,8 @@ def flag_whitespace_files(project):
14021402
whitespace_set = set(b" \n\r\t\f\b")
14031403

14041404
for resource in resources:
1405-
binary_data = open(resource.location, "rb").read()
1405+
with open(resource.location, "rb") as f:
1406+
binary_data = f.read()
14061407
binary_set = set(binary_data)
14071408
non_whitespace_bytes = binary_set - whitespace_set
14081409

scanpipe/pipes/resolve.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from packagedcode import APPLICATION_PACKAGE_DATAFILE_HANDLERS
3131
from packagedcode.licensing import get_license_detections_and_expression
3232
from packageurl import PackageURL
33-
from python_inspector.resolve_cli import resolver_api
33+
from python_inspector.api import resolve_dependencies
3434
from scancode.api import get_package_data
3535

3636
from scanpipe.models import DiscoveredPackage
@@ -64,7 +64,7 @@ def resolve_pypi_packages(input_location):
6464
python_version = f"{sys.version_info.major}{sys.version_info.minor}"
6565
operating_system = "linux"
6666

67-
inspector_output = resolver_api(
67+
inspector_output = resolve_dependencies(
6868
requirement_files=[input_location],
6969
python_version=python_version,
7070
operating_system=operating_system,

scanpipe/templates/scanpipe/base.html

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
.is-black-link {color: #363636;}
4040
.is-grey-link {color: #7a7a7a;}
4141
.is-black-link:hover, .is-grey-link:hover {color: #3273dc; text-decoration: underline;}
42+
.navbar button.navbar-item {font-size: 1em;}
4243
#inputs-panel .panel-block.dropdown:hover {background-color: #f5f5f5;}
4344
#inputs-panel .dropdown-menu {width: 85%;}
4445
a.panel-block {word-break: break-all;}

scanpipe/templates/scanpipe/includes/navbar_header.html

+6-3
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@
2727
<a class="navbar-item" href="{% url 'account_profile' %}">
2828
Profile settings
2929
</a>
30-
<a class="navbar-item" href="{% url 'logout' %}">
31-
Sign out
32-
</a>
30+
<form id="logout-form" method="post" action="{% url 'logout' %}">
31+
{% csrf_token %}
32+
<button class="navbar-item button is-white has-text-grey-dark is-fullwidth is-justify-content-flex-start" type="submit">
33+
Sign out
34+
</button>
35+
</form>
3336
<hr class="navbar-divider">
3437
<div class="navbar-item">
3538
<i>ScanCode.io {{ SCANCODEIO_VERSION }}</i>

scanpipe/tests/pipes/test_d2d.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -963,23 +963,23 @@ def test_scanpipe_pipes_d2d_get_project_resources_qs(self):
963963
"directory1/foo.txt",
964964
]
965965
expected_qs = self.project1.codebaseresources.filter(path__in=expected_paths)
966-
self.assertQuerysetEqual(expected_qs, resources_qs)
966+
self.assertQuerySetEqual(expected_qs, resources_qs)
967967

968968
def test_scanpipe_pipes_d2d_get_from_files_related_with_not_in_package_to_files(
969969
self,
970970
):
971971
from_resource1 = make_resource_file(self.project1, "from/foo.java")
972972
to_resource1 = make_resource_file(self.project1, "to/foo.class")
973973
qs = d2d.get_from_files_related_with_not_in_package_to_files(self.project1)
974-
self.assertQuerysetEqual([], qs)
974+
self.assertQuerySetEqual([], qs)
975975

976976
pipes.make_relation(from_resource1, to_resource1, "java_to_class")
977977
qs = d2d.get_from_files_related_with_not_in_package_to_files(self.project1)
978-
self.assertQuerysetEqual([], qs)
978+
self.assertQuerySetEqual([], qs)
979979

980980
from_resource1.update(detected_license_expression="mit")
981981
qs = d2d.get_from_files_related_with_not_in_package_to_files(self.project1)
982-
self.assertQuerysetEqual([from_resource1], qs)
982+
self.assertQuerySetEqual([from_resource1], qs)
983983

984984
def test_scanpipe_pipes_d2d_create_local_files_packages(self):
985985
from_resource1 = make_resource_file(

scanpipe/tests/pipes/test_js.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,11 @@ def test_scanpipe_pipes_js_get_map_sources_content(self):
133133
"resources/adaptive_media/js/main.js.map"
134134
)
135135
)
136-
expected = open(expected_location, "r").read()
137-
result = js.get_map_sources_content(to_resource)
138136

137+
with open(expected_location, "r") as f:
138+
expected = f.read()
139+
140+
result = js.get_map_sources_content(to_resource)
139141
self.assertEqual([expected], result)
140142

141143
def test_scanpipe_pipes_js_get_minified_resource(self):

scanpipe/tests/pipes/test_scancode.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,10 @@ def test_scanpipe_pipes_scancode_make_results_summary(self, regen=FIXTURES_REGEN
458458
uuid = "ba110d49-b6f2-4c86-8d89-a6fd34838ca8"
459459
package.update(package_uid=f"pkg:npm/[email protected]?uuid={uuid}")
460460

461-
# Patching the ``file_type`` values as those OS dependant.
461+
# Patching the ``file_type`` and ``mime_typea` values as those are OS dependant.
462462
# Note that we cannot use proper ``mock`` as the ``scan_package`` pipeline
463463
# uses a subprocess call to run the ``scancode`` command.
464-
project1.codebaseresources.all().update(file_type="")
464+
project1.codebaseresources.all().update(file_type="", mime_type="text/plain")
465465

466466
scan_output_location = self.data_location / "is-npm-1.0.0_scan_package.json"
467467
summary = scancode.make_results_summary(project1, scan_output_location)

scanpipe/tests/test_auth.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,18 @@ def test_scancodeio_auth_logged_in_navbar_header(self):
9595
self.assertContains(response, expected, html=True)
9696
expected = f'<a class="navbar-item" href="{profile_url}">Profile settings</a>'
9797
self.assertContains(response, expected, html=True)
98-
expected = f'<a class="navbar-item" href="{logout_url}">Sign out</a>'
99-
self.assertContains(response, expected, html=True)
98+
expected = f'<form id="logout-form" method="post" action="{logout_url}">'
99+
self.assertContains(response, expected)
100100

101101
def test_scancodeio_auth_logout_view(self):
102102
response = self.client.get(logout_url)
103+
self.assertEqual(405, response.status_code)
104+
105+
response = self.client.post(logout_url)
103106
self.assertRedirects(response, login_url)
104107

105108
self.client.login(username=self.basic_user.username, password=TEST_PASSWORD)
106-
response = self.client.get(logout_url)
109+
response = self.client.post(logout_url)
107110
self.assertRedirects(response, login_url)
108111

109112
def test_scancodeio_account_profile_view(self):

scanpipe/tests/test_models.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import uuid
2828
from contextlib import redirect_stdout
2929
from datetime import datetime
30+
from datetime import timezone as tz
3031
from pathlib import Path
3132
from unittest import mock
3233
from unittest import skipIf
@@ -754,11 +755,11 @@ def test_scanpipe_run_model_task_execution_time_property(self):
754755

755756
self.assertIsNone(run1.execution_time)
756757

757-
run1.task_start_date = datetime(1984, 10, 10, 10, 10, 10, tzinfo=timezone.utc)
758+
run1.task_start_date = datetime(1984, 10, 10, 10, 10, 10, tzinfo=tz.utc)
758759
run1.save()
759760
self.assertIsNone(run1.execution_time)
760761

761-
run1.task_end_date = datetime(1984, 10, 10, 10, 10, 35, tzinfo=timezone.utc)
762+
run1.task_end_date = datetime(1984, 10, 10, 10, 10, 35, tzinfo=tz.utc)
762763
run1.save()
763764
self.assertEqual(25.0, run1.execution_time)
764765

@@ -771,19 +772,19 @@ def test_scanpipe_run_model_execution_time_for_display_property(self):
771772

772773
self.assertIsNone(run1.execution_time_for_display)
773774

774-
run1.task_start_date = datetime(1984, 10, 10, 10, 10, 10, tzinfo=timezone.utc)
775+
run1.task_start_date = datetime(1984, 10, 10, 10, 10, 10, tzinfo=tz.utc)
775776
run1.save()
776777
self.assertIsNone(run1.execution_time_for_display)
777778

778-
run1.task_end_date = datetime(1984, 10, 10, 10, 10, 35, tzinfo=timezone.utc)
779+
run1.task_end_date = datetime(1984, 10, 10, 10, 10, 35, tzinfo=tz.utc)
779780
run1.save()
780781
self.assertEqual("25 seconds", run1.execution_time_for_display)
781782

782-
run1.task_end_date = datetime(1984, 10, 10, 10, 12, 35, tzinfo=timezone.utc)
783+
run1.task_end_date = datetime(1984, 10, 10, 10, 12, 35, tzinfo=tz.utc)
783784
run1.save()
784785
self.assertEqual("145 seconds (2.4 minutes)", run1.execution_time_for_display)
785786

786-
run1.task_end_date = datetime(1984, 10, 10, 11, 12, 35, tzinfo=timezone.utc)
787+
run1.task_end_date = datetime(1984, 10, 10, 11, 12, 35, tzinfo=tz.utc)
787788
run1.save()
788789
self.assertEqual("3745 seconds (1.0 hours)", run1.execution_time_for_display)
789790

scanpipe/tests/test_pipelines.py

+15-11
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,16 @@ def test_scanpipe_rootfs_pipeline_extract_input_files_errors(self):
253253
self.assertEqual("Error\nError", error.description)
254254

255255

256-
def sort_scanned_files_by_path(scan_data):
256+
def sort_for_os_compatibility(scan_data):
257257
"""
258-
Sort the ``scan_data`` files in place. Return ``scan_data``.
258+
Sort the ``scan_data`` files and relations in place. Return ``scan_data``.
259259
"""
260-
files = scan_data.get("files")
261-
if files:
260+
if files := scan_data.get("files"):
262261
files.sort(key=lambda x: x["path"])
262+
263+
if relations := scan_data.get("relations"):
264+
relations.sort(key=lambda x: x["to_resource"])
265+
263266
return scan_data
264267

265268

@@ -292,8 +295,9 @@ class PipelinesIntegrationTest(TestCase):
292295
# system_environment differs between systems
293296
"system_environment",
294297
"file_type",
295-
# mime type is inconsistent across systems
298+
# mime type and is_script are inconsistent across systems
296299
"mime_type",
300+
"is_script",
297301
"notes",
298302
"settings",
299303
"description",
@@ -381,15 +385,15 @@ def assertPipelineResultEqual(
381385
result_json = json.loads(Path(result_file).read_text())
382386
result_json = self._normalize_package_uids(result_json)
383387
result_data = self._without_keys(result_json, self.exclude_from_diff)
384-
result_data = sort_scanned_files_by_path(result_data)
388+
result_data = sort_for_os_compatibility(result_data)
385389

386390
if regen:
387391
expected_file.write_text(json.dumps(result_data, indent=2))
388392

389393
expected_json = json.loads(expected_file.read_text())
390394
expected_json = self._normalize_package_uids(expected_json)
391395
expected_data = self._without_keys(expected_json, self.exclude_from_diff)
392-
expected_data = sort_scanned_files_by_path(expected_data)
396+
expected_data = sort_for_os_compatibility(expected_data)
393397

394398
self.assertEqual(expected_data, result_data)
395399

@@ -766,23 +770,23 @@ def test_scanpipe_inspect_manifest_pipeline_integration_test(self):
766770
self.assertEqual(1, exitcode, msg=out)
767771
self.assertIn("No package type found for", out)
768772

769-
@mock.patch("scanpipe.pipes.resolve.resolver_api")
773+
@mock.patch("scanpipe.pipes.resolve.resolve_dependencies")
770774
def test_scanpipe_inspect_manifest_pipeline_pypi_integration_test(
771-
self, resolver_api
775+
self, resolve_dependencies
772776
):
773777
pipeline_name = "inspect_manifest"
774778
project1 = Project.objects.create(name="Analysis")
775779

776780
run = project1.add_pipeline(pipeline_name)
777781
pipeline = run.make_pipeline_instance()
778782

779-
resolver_api.return_value = mock.Mock(packages=[])
783+
resolve_dependencies.return_value = mock.Mock(packages=[])
780784
project1.move_input_from(tempfile.mkstemp(suffix="requirements.txt")[1])
781785
exitcode, out = pipeline.execute()
782786
self.assertEqual(1, exitcode, msg=out)
783787
self.assertIn("No packages could be resolved", out)
784788

785-
resolver_api.return_value = mock.Mock(packages=[package_data1])
789+
resolve_dependencies.return_value = mock.Mock(packages=[package_data1])
786790
exitcode, out = pipeline.execute()
787791
self.assertEqual(0, exitcode, msg=out)
788792

0 commit comments

Comments
 (0)