Skip to content

Commit

Permalink
chore: replace deprecated LegacyVersion with own one (#4043)
Browse files Browse the repository at this point in the history
* replace depreacted LegacyVersion with own one

* upgrade to latest packaging version

* fix mypy

* fix linting

* add ignorecase flag
  • Loading branch information
gruebel authored Dec 12, 2022
1 parent c6543a4 commit 2153e7c
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ jmespath = "*"
tqdm = "*"
update-checker = "*"
semantic-version = "*"
packaging = "==21.3"
packaging = "*"
cloudsplaining = ">=0.4.3"
networkx = "<2.7"
dockerfile-parse ="*"
Expand Down
30 changes: 7 additions & 23 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file.
141 changes: 141 additions & 0 deletions checkov/common/packaging/version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

# Partial copy of https://github.com/pypa/packaging/blob/21.3/packaging/version.py

from __future__ import annotations

import re
from typing import Iterator, TYPE_CHECKING

from packaging import version as packaging_version

if TYPE_CHECKING:
from typing_extensions import TypeAlias

LegacyCmpKey: TypeAlias = "tuple[int, tuple[str, ...]]"
Version = packaging_version.Version


def parse(version: str) -> packaging_version.Version | LegacyVersion:
"""
Parse the given version string and return either a :class:`Version` object
or a :class:`LegacyVersion` object depending on if the given version is
a valid PEP 440 version or a legacy version.
"""
try:
return packaging_version.parse(version)
except packaging_version.InvalidVersion:
return LegacyVersion(version)


class LegacyVersion(packaging_version._BaseVersion):
def __init__(self, version: str) -> None:
self._version = str(version)
self._key = _legacy_cmpkey(self._version) # type:ignore[assignment]

def __str__(self) -> str:
return self._version

def __repr__(self) -> str:
return f"<LegacyVersion('{self}')>"

@property
def public(self) -> str:
return self._version

@property
def base_version(self) -> str:
return self._version

@property
def epoch(self) -> int:
return -1

@property
def release(self) -> None:
return None

@property
def pre(self) -> None:
return None

@property
def post(self) -> None:
return None

@property
def dev(self) -> None:
return None

@property
def local(self) -> None:
return None

@property
def is_prerelease(self) -> bool:
return False

@property
def is_postrelease(self) -> bool:
return False

@property
def is_devrelease(self) -> bool:
return False


_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE | re.IGNORECASE)

_legacy_version_replacement_map = {
"pre": "c",
"preview": "c",
"-": "final-",
"rc": "c",
"dev": "@",
}


def _parse_version_parts(s: str) -> Iterator[str]:
for part in _legacy_version_component_re.split(s):
part = _legacy_version_replacement_map.get(part, part)

if not part or part == ".":
continue

if part[:1] in "0123456789":
# pad for numeric comparison
yield part.zfill(8)
else:
yield "*" + part

# ensure that alpha/beta/candidate are before final
yield "*final"


def _legacy_cmpkey(version: str) -> LegacyCmpKey:

# We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
# greater than or equal to 0. This will effectively put the LegacyVersion,
# which uses the defacto standard originally implemented by setuptools,
# as before all PEP 440 versions.
epoch = -1

# This scheme is taken from pkg_resources.parse_version setuptools prior to
# it's adoption of the packaging library.
parts: list[str] = []
for part in _parse_version_parts(version.lower()):
if part.startswith("*"):
# remove "-" before a prerelease tag
if part < "*final":
while parts and parts[-1] == "*final-":
parts.pop()

# remove trailing zeros from each series of numeric parts
while parts and parts[-1] == "00000000":
parts.pop()

parts.append(part)

return epoch, tuple(parts)
3 changes: 1 addition & 2 deletions checkov/common/sca/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
from datetime import datetime, timedelta
from typing import TYPE_CHECKING, Any, Optional, Dict, List

from packaging import version as packaging_version

from checkov.common.bridgecrew.integration_features.features.policy_metadata_integration import (
integration as metadata_integration,
)
Expand All @@ -15,6 +13,7 @@
from checkov.common.models.enums import CheckResult, ScanDataFormat
from checkov.common.output.extra_resource import ExtraResource
from checkov.common.output.record import Record, DEFAULT_SEVERITY, SCA_PACKAGE_SCAN_CHECK_NAME, SCA_LICENSE_CHECK_NAME
from checkov.common.packaging import version as packaging_version
from checkov.common.sca.commons import (
get_file_path_for_record,
get_resource_for_record,
Expand Down
2 changes: 1 addition & 1 deletion checkov/common/util/json_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
from typing import Any

from lark import Tree
from packaging.version import LegacyVersion, Version

from checkov.common.bridgecrew.severities import Severity
from checkov.common.output.common import ImageDetails
from checkov.common.packaging.version import LegacyVersion, Version


class CustomJSONEncoder(json.JSONEncoder):
Expand Down
2 changes: 1 addition & 1 deletion checkov/sca_package/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
from dataclasses import dataclass
from typing import List, Union, Dict, Any

from packaging import version as packaging_version
from prettytable import PrettyTable, SINGLE_BORDER

from checkov.common.bridgecrew.severities import Severities, BcSeverities
from checkov.common.models.enums import CheckResult
from checkov.common.output.record import Record, DEFAULT_SEVERITY, SCA_PACKAGE_SCAN_CHECK_NAME, SCA_LICENSE_CHECK_NAME
from checkov.common.packaging import version as packaging_version
from checkov.common.sca.commons import UNFIXABLE_VERSION
from checkov.common.typing import _LicenseStatus

Expand Down
2 changes: 1 addition & 1 deletion checkov/sca_package_2/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
from dataclasses import dataclass
from typing import List, Union, Dict, Any

from packaging import version as packaging_version
from prettytable import PrettyTable, SINGLE_BORDER

from checkov.common.bridgecrew.severities import Severities, BcSeverities
from checkov.common.models.enums import CheckResult
from checkov.common.output.record import Record, DEFAULT_SEVERITY, SCA_PACKAGE_SCAN_CHECK_NAME, SCA_LICENSE_CHECK_NAME
from checkov.common.packaging import version as packaging_version
from checkov.common.sca.commons import UNFIXABLE_VERSION, get_package_alias
from checkov.common.typing import _LicenseStatus

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import re
from typing import List, Dict, Optional

from packaging import version
from checkov.common.packaging import version

VERSION_REGEX = re.compile(r"^(?P<operator>=|!=|>=|>|<=|<|~>)?\s*(?P<version>[\d.]+-?\w*)$")

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"tqdm",
"update-checker",
"semantic-version",
"packaging==21.3",
"packaging",
"cloudsplaining>=0.4.3",
"networkx<2.7",
"dockerfile-parse",
Expand Down

0 comments on commit 2153e7c

Please sign in to comment.