Skip to content

Commit 500dc6c

Browse files
authored
fix(hashalgo): Merge PR 14
2 parents b6fef39 + fd7ba0a commit 500dc6c

5 files changed

Lines changed: 131 additions & 52 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "uv_build"
44

55
[project]
66
name = "python-ort"
7-
version = "0.4.0"
7+
version = "0.4.1"
88
description = "A Python Ort model serialization library"
99
readme = "README.md"
1010
license = "MIT"

src/ort/models/hash_algorithm.py

Lines changed: 107 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,116 @@
11
# SPDX-FileCopyrightText: 2025 Helio Chissini de Castro <heliocastro@gmail.com>
2-
#
32
# SPDX-License-Identifier: MIT
43

4+
from typing import ClassVar
55

6-
from enum import Enum
6+
from pydantic import BaseModel, Field, model_validator
77

88

9-
class HashAlgorithm(Enum):
9+
class HashAlgorithm(BaseModel):
1010
"""
11-
An enum of supported hash algorithms. Each algorithm has one or more [aliases] associated to it,
12-
where the first alias is the definite name.
13-
14-
Attributes:
15-
NONE: No hash algorithm.
16-
UNKNOWN: An unknown hash algorithm.
17-
MD5: The Message-Digest 5 hash algorithm, see [MD5](http://en.wikipedia.org/wiki/MD5).
18-
SHA1: The Secure Hash Algorithm 1, see [SHA-1](https://en.wikipedia.org/wiki/SHA-1).
19-
SHA256: The Secure Hash Algorithm 2 with 256 bits, see [SHA-256](https://en.wikipedia.org/wiki/SHA-256).
20-
SHA384: The Secure Hash Algorithm 2 with 384 bits, see [SHA-384](https://en.wikipedia.org/wiki/SHA-384).
21-
SHA512: The Secure Hash Algorithm 2 with 512 bits, see [SHA-512](https://en.wikipedia.org/wiki/SHA-512).
22-
SHA1GIT: The Secure Hash Algorithm 1, but calculated on a Git "blob" object, see
23-
- https://git-scm.com/book/en/v2/Git-Internals-Git-Objects#_object_storage
24-
- https://docs.softwareheritage.org/devel/swh-model/persistent-identifiers.html#git-compatibility
11+
A Python port of the Kotlin HashAlgorithm enum class.
12+
13+
Each algorithm has one or more aliases, an empty hash value,
14+
and an 'is_verifiable' flag.
2515
"""
2616

27-
NONE = "NONE"
28-
UNKNOWN = "UNKNOWN"
29-
MD5 = "MD5"
30-
SHA1 = "SHA1"
31-
SHA256 = "SHA256"
32-
SHA384 = "SHA384"
33-
SHA512 = "SHA512"
34-
SHA1GIT = (
35-
["SHA-1-GIT", "SHA1-GIT", "SHA1GIT", "SWHID"],
36-
"e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
37-
)
17+
aliases: list[str] = Field(default_factory=list)
18+
empty_value: str = ""
19+
is_verifiable: bool = True
20+
21+
# ---- known algorithms ----
22+
NONE: ClassVar["HashAlgorithm"]
23+
UNKNOWN: ClassVar["HashAlgorithm"]
24+
MD5: ClassVar["HashAlgorithm"]
25+
SHA1: ClassVar["HashAlgorithm"]
26+
SHA256: ClassVar["HashAlgorithm"]
27+
SHA384: ClassVar["HashAlgorithm"]
28+
SHA512: ClassVar["HashAlgorithm"]
29+
SHA1GIT: ClassVar["HashAlgorithm"]
30+
31+
# ---- derived property ----
32+
@property
33+
def size(self) -> int:
34+
"""The length of the empty hash string for this algorithm."""
35+
return len(self.empty_value)
36+
37+
# ---- validation ----
38+
@model_validator(mode="before")
39+
@classmethod
40+
def _from_alias(cls, value):
41+
"""Allow initialization from alias string."""
42+
if isinstance(value, str):
43+
algo = cls.from_string(value)
44+
return algo.model_dump()
45+
return value
46+
47+
# ---- class methods ----
48+
@classmethod
49+
def from_string(cls, alias: str) -> "HashAlgorithm":
50+
"""Find a HashAlgorithm by alias name (case-insensitive)."""
51+
alias_upper = alias.upper()
52+
for algo in cls._entries():
53+
if any(a.upper() == alias_upper for a in algo.aliases):
54+
return algo
55+
return cls.UNKNOWN
56+
57+
@classmethod
58+
def create(cls, value: str) -> "HashAlgorithm":
59+
"""
60+
Create a HashAlgorithm from a hash value string, based on its length.
61+
Returns NONE if value is blank, UNKNOWN otherwise.
62+
"""
63+
if not value.strip():
64+
return cls.NONE
65+
for algo in cls._entries():
66+
if len(value) == algo.size:
67+
return algo
68+
return cls.UNKNOWN
69+
70+
@classmethod
71+
def _entries(cls) -> list["HashAlgorithm"]:
72+
"""Return the list of all defined algorithms."""
73+
return [
74+
cls.NONE,
75+
cls.UNKNOWN,
76+
cls.MD5,
77+
cls.SHA1,
78+
cls.SHA256,
79+
cls.SHA384,
80+
cls.SHA512,
81+
cls.SHA1GIT,
82+
]
83+
84+
def __str__(self) -> str:
85+
return self.aliases[0] if self.aliases else ""
86+
87+
88+
HashAlgorithm.NONE = HashAlgorithm(aliases=[""], empty_value="", is_verifiable=False)
89+
HashAlgorithm.UNKNOWN = HashAlgorithm(aliases=["UNKNOWN"], empty_value="", is_verifiable=False)
90+
HashAlgorithm.MD5 = HashAlgorithm(
91+
aliases=["MD5"],
92+
empty_value="d41d8cd98f00b204e9800998ecf8427e",
93+
)
94+
HashAlgorithm.SHA1 = HashAlgorithm(
95+
aliases=["SHA-1", "SHA1"],
96+
empty_value="da39a3ee5e6b4b0d3255bfef95601890afd80709",
97+
)
98+
HashAlgorithm.SHA256 = HashAlgorithm(
99+
aliases=["SHA-256", "SHA256"],
100+
empty_value="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
101+
)
102+
HashAlgorithm.SHA384 = HashAlgorithm(
103+
aliases=["SHA-384", "SHA384"],
104+
empty_value=("38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b"),
105+
)
106+
HashAlgorithm.SHA512 = HashAlgorithm(
107+
aliases=["SHA-512", "SHA512"],
108+
empty_value=(
109+
"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce"
110+
"47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
111+
),
112+
)
113+
HashAlgorithm.SHA1GIT = HashAlgorithm(
114+
aliases=["SHA-1-GIT", "SHA1-GIT", "SHA1GIT", "SWHID"],
115+
empty_value="e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
116+
)

tests/data/example_curations.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
curations:
3232
comment: 'Repository moved to https://gitlab.ow2.org.'
3333
vcs:
34-
type: 'Giot'
34+
type: 'Git'
3535
url: 'https://gitlab.ow2.org/asm/asm.git'
3636

3737
- id: 'NPM::ast-traverse:0.1.0'
Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
1-
- id: "Maven:com.example.app:example:0.0.1"
1+
- id: 'Maven:com.example.app:example:0.0.1'
22
curations:
3-
comment: "An explanation why the curation is needed or the reasoning for a license conclusion"
4-
purl: "pkg:Maven/com.example.app/example@0.0.1?arch=arm64-v8a#src/main"
3+
comment: 'An explanation why the curation is needed or the reasoning for a license conclusion'
4+
purl: 'pkg:Maven/com.example.app/example@0.0.1?arch=arm64-v8a#src/main'
55
authors:
6-
- "Name of one author"
7-
- "Name of another author"
8-
cpe: "cpe:2.3:a:example-org:example-package:0.0.1:*:*:*:*:*:*:*"
9-
concluded_license: "Valid SPDX license expression to override the license findings."
6+
- 'Name of one author'
7+
- 'Name of another author'
8+
cpe: 'cpe:2.3:a:example-org:example-package:0.0.1:*:*:*:*:*:*:*'
9+
concluded_license: 'Valid SPDX license expression to override the license findings.'
1010
declared_license_mapping:
11-
"license a": "Apache-2.0"
12-
description: "Curated description."
13-
homepage_url: "http://example.com"
11+
'license a': 'Apache-2.0'
12+
description: 'Curated description.'
13+
homepage_url: 'http://example.com'
1414
binary_artifact:
15-
url: "http://example.com/binary.zip"
15+
url: 'http://example.com/binary.zip'
1616
hash:
17-
value: "ddce269a1e3d054cae349621c198dd52"
18-
algorithm: "MD5"
17+
value: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
18+
algorithm: 'SHA256'
1919
source_artifact:
20-
url: "http://example.com/sources.zip"
20+
url: 'http://example.com/sources.zip'
2121
hash:
22-
value: "ddce269a1e3d054cae349621c198dd52"
23-
algorithm: "MD5"
22+
value: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
23+
algorithm: 'SHA-256'
2424
vcs:
25-
type: "Git"
26-
url: "http://example.com/repo.git"
27-
revision: "1234abc"
28-
path: "subdirectory"
25+
type: 'Git'
26+
url: 'http://example.com/repo.git'
27+
revision: '1234abc'
28+
path: 'subdirectory'
2929
is_metadata_only: true
3030
is_modified: true
3131
source_code_origins: [ARTIFACT, VCS]
3232
labels:
33-
my-key: "my-value"
33+
my-key: 'my-value'

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)