Skip to content

Commit 37ec834

Browse files
authored
break(general): remove Python 3.7 (bridgecrewio#5605)
* remove Python 3.7 and replace deep_merge * fix lint * remove deep-merge from setup.py
1 parent c01a549 commit 37ec834

File tree

30 files changed

+475
-413
lines changed

30 files changed

+475
-413
lines changed

.github/workflows/pr-test.yml

+2-7
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
strategy:
5555
fail-fast: true
5656
matrix:
57-
python: ["3.7", "3.8", "3.9", "3.10", "3.11"] # TODO: remove 3.7 end of September
57+
python: ["3.8", "3.9", "3.10", "3.11"]
5858
runs-on: ubuntu-latest
5959
timeout-minutes: 30
6060
steps:
@@ -79,12 +79,7 @@ jobs:
7979
# remove venv, if exists
8080
pipenv --rm || true
8181
pipenv --python ${{ matrix.python }}
82-
# TODO: remove 3.7 end of September
83-
if [ ${{ matrix.python }} == '3.7' ]; then
84-
pipenv install --skip-lock --dev -v
85-
else
86-
pipenv install --dev -v
87-
fi
82+
pipenv install --dev -v
8883
pipenv run pip install redefine --index-url https://pip.redefine.dev
8984
- name: Unit tests
9085
env:

Pipfile

-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ boto3-stubs-lite = {extras = ["s3"], version = "*"}
4646
bc-python-hcl2 = "==0.3.51"
4747
bc-detect-secrets = "==1.4.30"
4848
bc-jsonpath-ng = "==1.5.9"
49-
deep-merge = "*"
5049
tabulate = "*"
5150
colorama="*"
5251
termcolor="*"

Pipfile.lock

+282-335
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1+
from __future__ import annotations
2+
13
from dataclasses import dataclass
2-
from typing import TYPE_CHECKING
4+
from typing import Literal
35

46
from checkov.common.graph.graph_builder.graph_components.block_types import BlockType as CommonBlockType
57

6-
if TYPE_CHECKING:
7-
from typing_extensions import Literal
8-
98

109
@dataclass
1110
class BlockType(CommonBlockType):
12-
PARAMETER: 'Literal["parameter"]' = "parameter"
11+
PARAMETER: Literal["parameter"] = "parameter"

checkov/bicep/graph_builder/graph_components/block_types.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from dataclasses import dataclass
2+
from typing import Literal
23

3-
from typing_extensions import Literal, TypeAlias
4+
from typing_extensions import TypeAlias # noqa[TC002]
45

56
from checkov.common.graph.graph_builder.graph_components.block_types import BlockType as CommonBlockType
67

checkov/bicep/graph_builder/local_graph.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
import logging
44
from enum import Enum
55
from pathlib import Path
6-
from typing import Any, TYPE_CHECKING, overload
6+
from typing import Any, TYPE_CHECKING, overload, Literal
77

88
from pycep.transformer import BicepElement
9-
from typing_extensions import Literal, TypeAlias
9+
from typing_extensions import TypeAlias # noqa[TC002]
1010

1111
from checkov.bicep.graph_builder.graph_components.block_types import BlockType
1212
from checkov.bicep.graph_builder.graph_components.blocks import BicepBlock

checkov/bicep/runner.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import os
44
import logging
55
from pathlib import Path
6-
from typing import cast, Type, TYPE_CHECKING, Any
6+
from typing import cast, Type, TYPE_CHECKING, Any, Literal
77

88
from typing_extensions import TypeAlias # noqa[TC002]
99

@@ -40,7 +40,6 @@
4040
from checkov.common.images.image_referencer import Image
4141
from networkx import DiGraph
4242
from pycep.typing import BicepJson
43-
from typing_extensions import Literal
4443

4544
_BicepContext: TypeAlias = "dict[str, dict[str, Any]]"
4645
_BicepDefinitions: TypeAlias = "dict[Path, BicepJson]"

checkov/cloudformation/graph_builder/variable_rendering/renderer.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
from __future__ import annotations
22

33
import logging
4-
from typing import TYPE_CHECKING, Tuple, List, Any, Dict, Optional, Callable
5-
6-
from typing_extensions import TypedDict
4+
from typing import TYPE_CHECKING, Tuple, List, Any, Dict, Optional, Callable, TypedDict
75

86
from checkov.cloudformation.graph_builder.graph_components.block_types import BlockType
97
from checkov.cloudformation.graph_builder.utils import get_referenced_vertices_in_value, find_all_interpolations

checkov/common/graph/graph_builder/graph_components/block_types.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
from __future__ import annotations
22

33
from dataclasses import dataclass
4-
from typing import cast, TYPE_CHECKING
5-
6-
if TYPE_CHECKING:
7-
from typing_extensions import Literal
4+
from typing import cast, Literal
85

96

107
@dataclass

checkov/common/multi_signature.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
from abc import ABCMeta
55
from functools import update_wrapper
66
from types import CodeType
7-
from typing import Callable, Any, TypeVar, cast
8-
from typing_extensions import Protocol
7+
from typing import Callable, Any, TypeVar, cast, Protocol
98

109
_MultiT = TypeVar("_MultiT")
1110

checkov/common/output/cyclonedx.py

+2-8
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@
33
import itertools
44
import logging
55
import os
6-
import sys
76
from datetime import datetime
7+
from importlib.metadata import version as meta_version
88
from pathlib import Path
99
from typing import TYPE_CHECKING, cast, Any
10-
from checkov.common.output.common import format_string_to_licenses, validate_lines
1110

1211
from cyclonedx.model import (
1312
XsUri,
@@ -33,7 +32,7 @@
3332
from cyclonedx.output import get_instance, OutputFormat
3433
from packageurl import PackageURL
3534

36-
from checkov.common.output.common import ImageDetails
35+
from checkov.common.output.common import format_string_to_licenses, validate_lines, ImageDetails
3736
from checkov.common.output.report import CheckType
3837
from checkov.common.output.cyclonedx_consts import (
3938
SCA_CHECKTYPES,
@@ -48,11 +47,6 @@
4847
from checkov.common.output.record import SCA_PACKAGE_SCAN_CHECK_NAME
4948
from checkov.common.sca.commons import UNFIXABLE_VERSION, get_fix_version
5049

51-
if sys.version_info >= (3, 8):
52-
from importlib.metadata import version as meta_version
53-
else:
54-
from importlib_metadata import version as meta_version
55-
5650
if TYPE_CHECKING:
5751
from checkov.common.output.extra_resource import ExtraResource
5852
from checkov.common.output.record import Record

checkov/common/output/spdx.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import logging
55
from datetime import datetime, timezone
66
from io import StringIO
7+
from typing import TYPE_CHECKING
78
from uuid import uuid4
89

910
from license_expression import get_spdx_licensing
@@ -19,6 +20,11 @@
1920
from checkov.common.output.report import Report
2021
from checkov.version import version
2122

23+
if TYPE_CHECKING:
24+
from boolean import Expression as LicenseExpression
25+
from spdx_tools.spdx.model import SpdxNoAssertion
26+
27+
2228
DOCUMENT_NAME = "checkov-sbom"
2329
SPDXREF = "SPDXRef-"
2430

@@ -60,14 +66,16 @@ def get_tag_value_output(self) -> str:
6066
def validate_licenses(self, package: Package, license_: str) -> None:
6167
if license_ and license_ not in ["Unknown license", "NOT_FOUND", "Unknown"]:
6268
split_licenses = license_.split(",")
63-
licenses = []
69+
licenses: list[LicenseExpression | SpdxNoAssertion | SpdxNone] = []
6470

6571
for lic in split_licenses:
6672
lic = lic.strip('"')
6773
try:
68-
licenses.append(get_spdx_licensing().parse(lic))
74+
license_expression = get_spdx_licensing().parse(lic)
75+
if license_expression is not None:
76+
licenses.append(license_expression)
6977
except Exception as e:
70-
logging.info(f"error occured when trying to parse the license:{split_licenses} due to error {e}")
78+
logging.info(f"error occurred when trying to parse the license:{split_licenses} due to error {e}")
7179
package.license_info_from_files = licenses
7280

7381
def create_package(self, check: Record | ExtraResource) -> Package:

checkov/common/runners/object_runner.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
from abc import abstractmethod
88
from collections.abc import Iterable
99
from pathlib import Path
10-
from typing import Any, TYPE_CHECKING, Callable
11-
from typing_extensions import TypedDict, TypeAlias
10+
from typing import Any, TYPE_CHECKING, Callable, TypedDict
11+
from typing_extensions import TypeAlias # noqa[TC002]
1212

1313
from checkov.common.checks_infra.registry import get_graph_checks_registry
1414
from checkov.common.models.enums import CheckResult

checkov/common/runners/runner_registry.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@
1212
from collections import defaultdict
1313
from collections.abc import Iterable
1414
from pathlib import Path
15-
from typing import List, Dict, Any, Optional, cast, TYPE_CHECKING, Type
16-
17-
from typing_extensions import Literal
15+
from typing import List, Dict, Any, Optional, cast, TYPE_CHECKING, Type, Literal
1816

1917
from checkov.common.bridgecrew.code_categories import CodeCategoryMapping, CodeCategoryType
2018
from checkov.common.bridgecrew.platform_integration import bc_integration

checkov/common/typing.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

3-
from typing import TYPE_CHECKING, Any, Callable, Dict, TypeVar, Set, Union
4-
from typing_extensions import TypeAlias, TypedDict
3+
from typing import TYPE_CHECKING, Any, Callable, Dict, TypeVar, Set, Union, TypedDict
4+
from typing_extensions import TypeAlias # noqa[TC002]
55

66
if TYPE_CHECKING:
77
from checkov.common.bridgecrew.severities import Severity

checkov/common/util/deep_merge.py

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
"""Original code: https://github.com/halfak/deep_merge"""
2+
from __future__ import annotations
3+
4+
from typing import Any, TypeVar, Callable, Protocol
5+
6+
from typing_extensions import TypeAlias # noqa[TC002]
7+
8+
from checkov.common.util.data_structures_utils import pickle_deepcopy
9+
10+
_T = TypeVar("_T")
11+
_MergeDict = TypeVar("_MergeDict", bound="dict[Any, Any]")
12+
_OverwriteFunc: TypeAlias = "Callable[..., Any]"
13+
14+
15+
class _MergeDictsFunc(Protocol):
16+
def __call__(
17+
self,
18+
d1: _MergeDict,
19+
d2: _MergeDict,
20+
*,
21+
merge_lists: _OverwriteFunc,
22+
merge_ints: _OverwriteFunc,
23+
merge_floats: _OverwriteFunc,
24+
merge_strings: _OverwriteFunc,
25+
merge_other: _OverwriteFunc,
26+
) -> _MergeDict:
27+
...
28+
29+
30+
def overwrite(v1: _T, v2: _T, **kwargs: Any) -> _T:
31+
"""
32+
Completely overwrites one value with another.
33+
"""
34+
return pickle_deepcopy(v2)
35+
36+
37+
def merge_dicts(
38+
d1: _MergeDict,
39+
d2: _MergeDict,
40+
merge_lists: _OverwriteFunc = overwrite,
41+
merge_ints: _OverwriteFunc = overwrite,
42+
merge_floats: _OverwriteFunc = overwrite,
43+
merge_strings: _OverwriteFunc = overwrite,
44+
merge_other: _OverwriteFunc = overwrite,
45+
) -> _MergeDict:
46+
"""
47+
Recursively merges values from d2 into d1.
48+
"""
49+
kwargs = {
50+
"merge_lists": merge_lists,
51+
"merge_ints": merge_ints,
52+
"merge_floats": merge_floats,
53+
"merge_strings": merge_strings,
54+
"merge_other": merge_other,
55+
}
56+
for key in d2:
57+
if key in d1:
58+
if isinstance(d1[key], dict) and isinstance(d2[key], dict):
59+
d1[key] = merge_dicts(d1[key], d2[key], **kwargs)
60+
elif isinstance(d1[key], list) and isinstance(d2[key], list):
61+
d1[key] = merge_lists(d1[key], d2[key], **kwargs)
62+
elif isinstance(d1[key], int) and isinstance(d2[key], int):
63+
d1[key] = merge_ints(d1[key], d2[key], **kwargs)
64+
elif isinstance(d1[key], float) and isinstance(d2[key], float):
65+
d1[key] = merge_ints(d1[key], d2[key], **kwargs)
66+
elif isinstance(d1[key], str) and isinstance(d2[key], str):
67+
d1[key] = merge_strings(d1[key], d2[key], **kwargs)
68+
else:
69+
d1[key] = merge_other(d1[key], d2[key], **kwargs)
70+
else:
71+
d1[key] = overwrite(None, d2[key])
72+
73+
return d1
74+
75+
76+
def pickle_deep_merge(
77+
*dicts: _MergeDict,
78+
merge_dicts: _MergeDictsFunc = merge_dicts,
79+
merge_lists: _OverwriteFunc = overwrite,
80+
merge_ints: _OverwriteFunc = overwrite,
81+
merge_floats: _OverwriteFunc = overwrite,
82+
merge_strings: _OverwriteFunc = overwrite,
83+
merge_other: _OverwriteFunc = overwrite,
84+
) -> _MergeDict:
85+
"""
86+
Recursively merges dictionaries and the datastructures they contain.
87+
88+
:Parameters:
89+
*dicts : `dict`
90+
Dictionaries to be merged. Items that appear last will take higher
91+
precedence when merging.
92+
merge_dicts : `func`
93+
The function to apply when merging dictionaries.
94+
merge_lists : `func`
95+
The function to apply when merging lists.
96+
merge_ints : `func`
97+
The function to apply when merging integers.
98+
merge_floats : `func`
99+
The function to apply when merging floats.
100+
merge_strings : `func`
101+
The function to apply when merging strings.
102+
merge_other : `func`
103+
The function to apply when merging other types or types that do not
104+
match.
105+
"""
106+
for param in dicts:
107+
if not isinstance(param, dict):
108+
raise TypeError("{0} is not a dict".format(param))
109+
110+
d = dicts[0]
111+
for d_update in dicts[1:]:
112+
d = merge_dicts(
113+
d,
114+
d_update,
115+
merge_lists=merge_lists,
116+
merge_ints=merge_ints,
117+
merge_floats=merge_floats,
118+
merge_strings=merge_strings,
119+
merge_other=merge_other,
120+
)
121+
122+
return d

checkov/common/util/http_utils.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,10 @@ async def aiohttp_client_session_wrapper(
208208
request_max_tries = int(os.getenv('REQUEST_MAX_TRIES', 3))
209209
sleep_between_request_tries = float(os.getenv('SLEEP_BETWEEN_REQUEST_TRIES', 1))
210210

211-
try: # TODO: test again, when Python 3.11 is out
212-
import aiodns # type: ignore[import] # noqa: F401
213-
resolver: "aiohttp.abc.AbstractResolver" = aiohttp.AsyncResolver()
214-
except ImportError:
215-
resolver = aiohttp.ThreadedResolver()
216-
217211
# adding retry mechanism for avoiding the next repeated unexpected issues:
218212
# 1. Gateway Timeout from the server
219213
# 2. ClientOSError
220-
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(resolver=resolver)) as session:
214+
async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(resolver=aiohttp.AsyncResolver())) as session:
221215
for i in range(request_max_tries):
222216
logging.info(
223217
f"[http_utils](aiohttp_client_session_wrapper) reporting attempt {i + 1} out of {request_max_tries}")

checkov/dockerfile/utils.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import os
55
from collections.abc import Iterable
66
from pathlib import Path
7-
from typing import TYPE_CHECKING, Callable, Any
7+
from typing import TYPE_CHECKING, Callable, Any, Literal
88

99
from dockerfile_parse.constants import COMMENT_INSTRUCTION
1010

@@ -15,7 +15,6 @@
1515

1616
if TYPE_CHECKING:
1717
from dockerfile_parse.parser import _Instruction # only in extra_stubs
18-
from typing_extensions import Literal
1918

2019
DOCKERFILE_STARTLINE: Literal["startline"] = "startline"
2120
DOCKERFILE_ENDLINE: Literal["endline"] = "endline"

0 commit comments

Comments
 (0)