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

feat(general): initial support for python 3.13 #6962

Merged
merged 15 commits into from
Jan 23, 2025
16 changes: 9 additions & 7 deletions .github/workflows/pr-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
strategy:
fail-fast: true
matrix:
python: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
tjwald marked this conversation as resolved.
Show resolved Hide resolved
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Expand All @@ -88,9 +88,9 @@ jobs:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install pipenv
run: |
if [ '${{ matrix.python }}' == '3.12' ]; then
if [ "${{ matrix.python }}" = "3.12" ] || [ "${{ matrix.python }}" = "3.13" ]; then
# needed for numpy
python -m pip install --no-cache-dir --upgrade pipenv==2024.0.3
python -m pip install --no-cache-dir --upgrade pipenv==2024.4.0
else
python -m pip install --no-cache-dir --upgrade pipenv
fi
Expand All @@ -100,7 +100,9 @@ jobs:
pipenv --rm || true
pipenv --python ${{ matrix.python }}

if [ '${{ matrix.python }}' == '3.12' ]; then
if [ "${{ matrix.python }}" = "3.12" ] || [ "${{ matrix.python }}" = "3.13" ]; then
echo "patching >3.12 issues"
pipenv run pip install setuptools
# needed for numpy
pipenv install --skip-lock --dev -v
else
Expand All @@ -119,7 +121,7 @@ jobs:
strategy:
fail-fast: true
matrix:
python: ["3.10", "3.11", "3.12"]
python: ["3.10", "3.11", "3.12", "3.13"]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -229,7 +231,7 @@ jobs:
strategy:
fail-fast: true
matrix:
python: ["3.12"]
python: ["3.12", "3.13"]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down Expand Up @@ -325,7 +327,7 @@ jobs:
strategy:
fail-fast: true
matrix:
python: ["3.12"]
python: ["3.12", "3.13"]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
Expand Down
7 changes: 3 additions & 4 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pytest-xdist = "*"
pytest-asyncio = "*"
pytest-cov = "*"
pytest-mock = "*"
coverage ="==5.5"
coverage ="==7.6.1"
coverage-badge = "*"
bandit = "*"
urllib3-mock = "*"
Expand All @@ -31,7 +31,7 @@ types-urllib3 = "*"
pre-commit = "*"
flake8 = "*"
dlint = "*"
mypy = "*"
mypy = "==1.13.0"
tjwald marked this conversation as resolved.
Show resolved Hide resolved
flake8-bugbear = "*"
parameterized = "*"
time-machine = "*"
Expand Down Expand Up @@ -86,6 +86,5 @@ license-expression = ">=30.1.0,<31.0.0"
rustworkx = ">=0.13.0,<0.14.0"
pydantic = ">=2.0.0,<3.0.0"


[requires]
python_version = "3.8"
python_version = ">=3.8.0,<3.14"
tjwald marked this conversation as resolved.
Show resolved Hide resolved
848 changes: 422 additions & 426 deletions Pipfile.lock

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions checkov/common/parallelizer/parallel_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
_T = TypeVar("_T")


class ParallelRunException(Exception):
def __init__(self, internal_exception: Exception) -> None:
self.internal_exception = internal_exception
super().__init__("Parallel run failed", internal_exception)


class ParallelRunner:
def __init__(
self, workers_number: int | None = None,
Expand Down Expand Up @@ -72,12 +78,12 @@ def func_wrapper(original_func: Callable[[Any], _T], items_group: List[Any], con
result = original_func(*item)
else:
result = original_func(item)
except Exception:
except Exception as e:
logging.error(
f"Failed to invoke function {func.__code__.co_filename.replace('.py', '')}.{func.__name__} with {item}",
exc_info=True,
)
result = None
result = ParallelRunException(e)
tjwald marked this conversation as resolved.
Show resolved Hide resolved

connection.send(result)
connection.close()
Expand All @@ -97,7 +103,12 @@ def func_wrapper(original_func: Callable[[Any], _T], items_group: List[Any], con
for _, parent_conn, group_len in processes:
for _ in range(group_len):
try:
yield parent_conn.recv()
v = parent_conn.recv()

if isinstance(v, ParallelRunException):
raise v.internal_exception

yield v
except EOFError:
pass

Expand Down
14 changes: 10 additions & 4 deletions checkov/secrets/scan_git_history.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import logging
import os
import platform
from typing import TYPE_CHECKING, Optional, List, Tuple
from typing import TYPE_CHECKING, Optional, List, Tuple, Union

from detect_secrets.core import scan

Expand Down Expand Up @@ -149,6 +149,7 @@ def _get_commits_diff(self, last_commit_sha: Optional[str] = None) -> List[Commi
)
for file_diff in git_diff:
file_name = file_diff.a_path if file_diff.a_path else file_diff.b_path
assert file_name is not None
if file_name.endswith(FILES_TO_IGNORE_IN_GIT_HISTORY):
continue
file_path = os.path.join(self.root_folder, file_name)
Expand All @@ -157,8 +158,8 @@ def _get_commits_diff(self, last_commit_sha: Optional[str] = None) -> List[Commi
logging.debug(f"File was renamed from {file_diff.rename_from} to {file_diff.rename_to}")
curr_diff.rename_file(
file_path=file_path,
prev_filename=file_diff.rename_from,
new_filename=file_diff.rename_to
prev_filename=file_diff.rename_from or "",
new_filename=file_diff.rename_to or ""
)
continue

Expand Down Expand Up @@ -241,6 +242,7 @@ def _get_first_commit(self) -> Commit:

for file_diff in git_diff:
file_name = file_diff.b_path
assert file_name is not None
if file_name.endswith(FILES_TO_IGNORE_IN_GIT_HISTORY):
continue
file_path = os.path.join(self.root_folder, file_name)
Expand All @@ -250,9 +252,13 @@ def _get_first_commit(self) -> Commit:
return first_commit_diff

@staticmethod
def get_decoded_diff(diff: bytes) -> str:
def get_decoded_diff(diff: Union[str, bytes, None]) -> str:
if diff is None:
return ''

if isinstance(diff, str):
return diff

try:
decoded_diff = diff.decode('utf-8')
except UnicodeDecodeError as ue:
Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ def run(self) -> None:
],
extras_require={
"dev": [
"pytest==5.3.1",
"coverage==5.5",
"pytest<8.0.0",
"coverage==7.6.1",
"coverage-badge",
"GitPython==3.1.41",
"bandit",
Expand Down Expand Up @@ -107,7 +107,7 @@ def run(self) -> None:
"spdx-tools>=0.8.0,<0.9.0",
"license-expression<31.0.0,>=30.1.0",
"rustworkx>=0.13.0,<0.14.0",
"pydantic<3.0.0,>=2.0.0"
"pydantic<3.0.0,>=2.0.0",
],
dependency_links=[], # keep it empty, needed for pipenv-setup
license="Apache License 2.0",
Expand Down
9 changes: 7 additions & 2 deletions tests/common/checks/test_base_check.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import unittest
from typing import List

from unittest import mock
from parameterized import parameterized
Expand Down Expand Up @@ -63,6 +64,10 @@ def scan_entity_conf(self, conf, entity_type):
return CheckResult.FAILED


def _clean_doc(st: str) -> List[str]:
return [line.strip() for line in st.splitlines() if not line.isspace()]


# noinspection DuplicatedCode
class TestBaseCheck(unittest.TestCase):

Expand All @@ -74,11 +79,11 @@ def test_entity_type_is_not_required_in_signature(self):
# noinspection PyArgumentList
scan_result = check.scan_entity_conf({}, "Some name")
self.assertEqual(CheckResult.PASSED, scan_result)
self.assertEqual(check.scan_entity_conf.__doc__, """
self.assertEqual(_clean_doc(check.scan_entity_conf.__doc__), _clean_doc("""
My documentation
:param conf:
:return:
""")
"""))

def test_invalid_signature_is_detected(self):
with self.assertRaises(TypeError) as context:
Expand Down
8 changes: 3 additions & 5 deletions tests/sca_package_2/test_output_reports.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import json
import sys
import xml
import xml.dom.minidom
import os
from operator import itemgetter
from pathlib import Path
from typing import List
from unittest import mock

import pytest
from pytest_mock import MockerFixture

from checkov.common.bridgecrew.check_type import CheckType
Expand All @@ -31,7 +28,8 @@ def _get_deterministic_items_in_cyclonedx(pretty_xml_as_list: List[str]) -> List
if not any(word in line for word in black_list_words):
if i == 0 or not any(tool_name in pretty_xml_as_list[i - 1] for tool_name in
("<name>checkov</name>", "<name>cyclonedx-python-lib</name>")):
filtered_list.append(line)
filtered_list.append(
line.replace('&quot;', '\"')) # fixes differences in xml prettyprint between python 3.12 and 3.13
return filtered_list


Expand Down Expand Up @@ -153,7 +151,7 @@ def test_get_cyclonedx_report(sca_package_2_report, tmp_path: Path):
actual_pretty_xml_as_list = _get_deterministic_items_in_cyclonedx(pretty_xml_as_string.split("\n"))
expected_pretty_xml_as_list = _get_deterministic_items_in_cyclonedx(expected_pretty_xml.split("\n"))

assert actual_pretty_xml_as_list == expected_pretty_xml_as_list
assert '\n'.join(actual_pretty_xml_as_list) == '\n'.join(expected_pretty_xml_as_list)


def test_get_cyclonedx_report_with_licenses_with_comma(sca_package_report_2_with_comma_in_licenses, tmp_path: Path):
Expand Down
Loading