From bc113cdad1bc53f7bbba6fb0b6283c89b00cf04f Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Tue, 27 Aug 2024 11:43:40 -0700 Subject: [PATCH 1/3] ADd support for Python3.10 Signed-off-by: Mihai Maruseac --- pyproject.toml | 5 ++-- src/model_signing/hashing/file.py | 24 +++++++++++++++---- src/model_signing/manifest/manifest.py | 8 ++++++- src/model_signing/signing/as_bytes.py | 8 ++++++- src/model_signing/signing/empty_signing.py | 8 ++++++- src/model_signing/signing/in_toto.py | 9 ++++++- .../signing/in_toto_signature.py | 8 ++++++- src/model_signing/signing/signing.py | 8 ++++++- src/model_signing/signing/sigstore.py | 8 ++++++- tests/signing/empty_signing_test.py | 8 ++++++- tests/signing/sigstore_test.py | 8 ++++++- 11 files changed, 86 insertions(+), 16 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 088026b0..443031f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ classifiers = [ "License :: OSI Approved :: Apache Software License", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Development Status :: 3 - Alpha", @@ -30,7 +31,7 @@ dependencies = [ "sigstore", "typing_extensions", ] -requires-python = ">=3.11" +requires-python = ">=3.10" keywords = [ "machine learning", "artificial intelligence", @@ -61,7 +62,7 @@ parallel = true randomize = true [[tool.hatch.envs.hatch-test.matrix]] -python = ["3.11", "3.12"] +python = ["3.10", "3.11", "3.12"] [tool.hatch.envs.docs] description = """Custom environment for pdoc. diff --git a/src/model_signing/hashing/file.py b/src/model_signing/hashing/file.py index eb2e599b..d4536ffc 100644 --- a/src/model_signing/hashing/file.py +++ b/src/model_signing/hashing/file.py @@ -48,6 +48,7 @@ import hashlib import pathlib +import sys from typing import BinaryIO from typing_extensions import override @@ -192,11 +193,24 @@ def digest_name(self) -> str: @override def compute(self) -> hashing.Digest: - # https://github.com/python/typeshed/issues/2166 - # pytype: disable=wrong-arg-types - digest = hashlib.file_digest(self._fd, self._algorithm) - # pytype: enable=wrong-arg-types - return hashing.Digest(self.digest_name, digest.digest()) + if sys.version_info >= (3, 11): + # https://github.com/python/typeshed/issues/2166 + # pytype: disable=wrong-arg-types + digest = hashlib.file_digest(self._fd, self._algorithm) + # pytype: enable=wrong-arg-types + return hashing.Digest(self.digest_name, digest.digest()) + else: + # Polyfill for Python 3.10 + # See https://github.com/python/cpython/blob/4deb32a99292a3b1f6b773f6f96f1a8990a19fe0/Lib/hashlib.py#L195-L238 + hasher = hashlib.new(self._algorithm) + buffer = bytearray(2**18) + view = memoryview(buffer) + while True: + size = self._fd.readinto(buffer) + if size == 0: + break + hasher.update(view[:size]) + return hashing.Digest(self.digest_name, hasher.digest()) @property @override diff --git a/src/model_signing/manifest/manifest.py b/src/model_signing/manifest/manifest.py index d6a5f34b..ce0efde6 100644 --- a/src/model_signing/manifest/manifest.py +++ b/src/model_signing/manifest/manifest.py @@ -55,13 +55,19 @@ from collections.abc import Iterable, Iterator import dataclasses import pathlib -from typing import Self +import sys from typing_extensions import override from model_signing.hashing import hashing +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + @dataclasses.dataclass(frozen=True) class ResourceDescriptor: """A description of any content from any `Manifest`. diff --git a/src/model_signing/signing/as_bytes.py b/src/model_signing/signing/as_bytes.py index eb3443af..dcc0ceba 100644 --- a/src/model_signing/signing/as_bytes.py +++ b/src/model_signing/signing/as_bytes.py @@ -18,7 +18,7 @@ the hash computed from somewhere else and want to avoid the in-toto types. """ -from typing import Self +import sys from typing_extensions import override @@ -26,6 +26,12 @@ from model_signing.signing import signing +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + class BytesPayload(signing.SigningPayload): """A payload that is a view into the bytes of a digest.""" diff --git a/src/model_signing/signing/empty_signing.py b/src/model_signing/signing/empty_signing.py index e3bbe5d9..bd78312f 100644 --- a/src/model_signing/signing/empty_signing.py +++ b/src/model_signing/signing/empty_signing.py @@ -21,7 +21,7 @@ """ import pathlib -from typing import Self +import sys from typing_extensions import override @@ -29,6 +29,12 @@ from model_signing.signing import signing +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + class EmptySigningPayload(signing.SigningPayload): """An empty signing payload, mostly just for testing.""" diff --git a/src/model_signing/signing/in_toto.py b/src/model_signing/signing/in_toto.py index 90e4e042..353df9c2 100644 --- a/src/model_signing/signing/in_toto.py +++ b/src/model_signing/signing/in_toto.py @@ -20,7 +20,8 @@ """ import pathlib -from typing import Any, Final, Self +import sys +from typing import Any, Final from in_toto_attestation.v1 import statement from typing_extensions import override @@ -31,6 +32,12 @@ from model_signing.signing import signing +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + class IntotoPayload(signing.SigningPayload): """A generic payload in in-toto format. diff --git a/src/model_signing/signing/in_toto_signature.py b/src/model_signing/signing/in_toto_signature.py index 83e3bf01..d6500b8c 100644 --- a/src/model_signing/signing/in_toto_signature.py +++ b/src/model_signing/signing/in_toto_signature.py @@ -16,7 +16,7 @@ import json import pathlib -from typing import Self +import sys from sigstore_protobuf_specs.dev.sigstore.bundle import v1 as bundle_pb from typing_extensions import override @@ -28,6 +28,12 @@ from model_signing.signing import signing +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + class IntotoSignature(signing.Signature): def __init__(self, bundle: bundle_pb.Bundle): self._bundle = bundle diff --git a/src/model_signing/signing/signing.py b/src/model_signing/signing/signing.py index 1ab8909b..d0d0e20c 100644 --- a/src/model_signing/signing/signing.py +++ b/src/model_signing/signing/signing.py @@ -43,11 +43,17 @@ import abc import pathlib -from typing import Self +import sys from model_signing.manifest import manifest +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + class SigningPayload(metaclass=abc.ABCMeta): """Generic payload that we can sign.""" diff --git a/src/model_signing/signing/sigstore.py b/src/model_signing/signing/sigstore.py index ff8dd465..b33f0adf 100644 --- a/src/model_signing/signing/sigstore.py +++ b/src/model_signing/signing/sigstore.py @@ -16,7 +16,7 @@ import json import pathlib -from typing import Self +import sys from google.protobuf import json_format from sigstore import dsse as sigstore_dsse @@ -33,6 +33,12 @@ from model_signing.signing import signing +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + _IN_TOTO_JSON_PAYLOAD_TYPE: str = "application/vnd.in-toto+json" _IN_TOTO_STATEMENT_TYPE: str = "https://in-toto.io/Statement/v1" diff --git a/tests/signing/empty_signing_test.py b/tests/signing/empty_signing_test.py index 0ac5239e..102e8af6 100644 --- a/tests/signing/empty_signing_test.py +++ b/tests/signing/empty_signing_test.py @@ -13,7 +13,7 @@ # limitations under the License. import pathlib -from typing import Self +import sys import pytest from typing_extensions import override @@ -25,6 +25,12 @@ from tests import test_support +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + class TestEmptySigningPayload: def test_build_from_digest_manifest(self): digest = hashing.Digest("test", b"test_digest") diff --git a/tests/signing/sigstore_test.py b/tests/signing/sigstore_test.py index 6eceedd5..1f069f66 100644 --- a/tests/signing/sigstore_test.py +++ b/tests/signing/sigstore_test.py @@ -16,7 +16,7 @@ import json import pathlib -from typing import Self +import sys from unittest import mock import pytest @@ -31,6 +31,12 @@ from model_signing.signing import sigstore +if sys.version_info >= (3, 11): + from typing import Self +else: + from typing_extensions import Self + + class MockedSigstoreBundle: """Mocked SigstoreBundle that just records the signed payload.""" From 80dc98fb5636bf65fcbbad129075680a893e784c Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Tue, 27 Aug 2024 11:46:55 -0700 Subject: [PATCH 2/3] Run CI on py3.10 too Signed-off-by: Mihai Maruseac --- .github/workflows/unit_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 0d21b555..39a6fd28 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -35,7 +35,7 @@ jobs: fail-fast: false # Don't cancel other jobs if one fails matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ['3.11', '3.12'] + python-version: ['3.10', '3.11', '3.12'] steps: - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Set up Hatch From ca798cffa58fe433cab2f90224b9657688639a2c Mon Sep 17 00:00:00 2001 From: Mihai Maruseac Date: Tue, 27 Aug 2024 12:58:06 -0700 Subject: [PATCH 3/3] Reduce some indentation Signed-off-by: Mihai Maruseac --- src/model_signing/hashing/file.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/model_signing/hashing/file.py b/src/model_signing/hashing/file.py index d4536ffc..109656c0 100644 --- a/src/model_signing/hashing/file.py +++ b/src/model_signing/hashing/file.py @@ -199,18 +199,18 @@ def compute(self) -> hashing.Digest: digest = hashlib.file_digest(self._fd, self._algorithm) # pytype: enable=wrong-arg-types return hashing.Digest(self.digest_name, digest.digest()) - else: - # Polyfill for Python 3.10 - # See https://github.com/python/cpython/blob/4deb32a99292a3b1f6b773f6f96f1a8990a19fe0/Lib/hashlib.py#L195-L238 - hasher = hashlib.new(self._algorithm) - buffer = bytearray(2**18) - view = memoryview(buffer) - while True: - size = self._fd.readinto(buffer) - if size == 0: - break - hasher.update(view[:size]) - return hashing.Digest(self.digest_name, hasher.digest()) + + # Polyfill for Python 3.10 + # https://github.com/python/cpython/blob/4deb32a992/Lib/hashlib.py#L195 + hasher = hashlib.new(self._algorithm) + buffer = bytearray(2**18) + view = memoryview(buffer) + while True: + size = self._fd.readinto(buffer) + if size == 0: + break + hasher.update(view[:size]) + return hashing.Digest(self.digest_name, hasher.digest()) @property @override