|
3 | 3 | import hashlib
|
4 | 4 | import io
|
5 | 5 |
|
| 6 | +from contextlib import suppress |
6 | 7 | from pathlib import Path
|
7 | 8 | from typing import TYPE_CHECKING
|
8 | 9 | from typing import Any
|
| 10 | +from typing import NamedTuple |
9 | 11 |
|
10 | 12 | import requests
|
11 | 13 |
|
@@ -48,6 +50,59 @@ def __init__(self, error: ConnectionError | HTTPError | str) -> None:
|
48 | 50 | super().__init__(message)
|
49 | 51 |
|
50 | 52 |
|
| 53 | +class Hexdigest(NamedTuple): |
| 54 | + md5: str | None |
| 55 | + sha256: str | None |
| 56 | + blake2_256: str | None |
| 57 | + |
| 58 | + |
| 59 | +class HashManager: |
| 60 | + def __init__(self) -> None: |
| 61 | + self._sha2_hasher = hashlib.sha256() |
| 62 | + |
| 63 | + self._md5_hasher = None |
| 64 | + with suppress(ValueError): |
| 65 | + # FIPS mode disables MD5 |
| 66 | + self._md5_hasher = hashlib.md5() |
| 67 | + |
| 68 | + self._blake_hasher = None |
| 69 | + with suppress(ValueError, TypeError): |
| 70 | + # FIPS mode disables blake2 |
| 71 | + self._blake_hasher = hashlib.blake2b(digest_size=256 // 8) |
| 72 | + |
| 73 | + def _md5_update(self, content: bytes) -> None: |
| 74 | + if self._md5_hasher is not None: |
| 75 | + self._md5_hasher.update(content) |
| 76 | + |
| 77 | + def _md5_hexdigest(self) -> str | None: |
| 78 | + if self._md5_hasher is not None: |
| 79 | + return self._md5_hasher.hexdigest() |
| 80 | + return None |
| 81 | + |
| 82 | + def _blake_update(self, content: bytes) -> None: |
| 83 | + if self._blake_hasher is not None: |
| 84 | + self._blake_hasher.update(content) |
| 85 | + |
| 86 | + def _blake_hexdigest(self) -> str | None: |
| 87 | + if self._blake_hasher is not None: |
| 88 | + return self._blake_hasher.hexdigest() |
| 89 | + return None |
| 90 | + |
| 91 | + def hash(self, file: Path) -> None: |
| 92 | + with file.open("rb") as fp: |
| 93 | + for content in iter(lambda: fp.read(io.DEFAULT_BUFFER_SIZE), b""): |
| 94 | + self._md5_update(content) |
| 95 | + self._sha2_hasher.update(content) |
| 96 | + self._blake_update(content) |
| 97 | + |
| 98 | + def hexdigest(self) -> Hexdigest: |
| 99 | + return Hexdigest( |
| 100 | + self._md5_hexdigest(), |
| 101 | + self._sha2_hasher.hexdigest(), |
| 102 | + self._blake_hexdigest(), |
| 103 | + ) |
| 104 | + |
| 105 | + |
51 | 106 | class Uploader:
|
52 | 107 | def __init__(self, poetry: Poetry, io: IO, dist_dir: Path | None = None) -> None:
|
53 | 108 | self._poetry = poetry
|
@@ -126,19 +181,13 @@ def post_data(self, file: Path) -> dict[str, Any]:
|
126 | 181 |
|
127 | 182 | file_type = self._get_type(file)
|
128 | 183 |
|
129 |
| - blake2_256_hash = hashlib.blake2b(digest_size=256 // 8) |
130 |
| - |
131 |
| - md5_hash = hashlib.md5() |
132 |
| - sha256_hash = hashlib.sha256() |
133 |
| - with file.open("rb") as fp: |
134 |
| - for content in iter(lambda: fp.read(io.DEFAULT_BUFFER_SIZE), b""): |
135 |
| - md5_hash.update(content) |
136 |
| - sha256_hash.update(content) |
137 |
| - blake2_256_hash.update(content) |
| 184 | + hash_manager = HashManager() |
| 185 | + hash_manager.hash(file) |
| 186 | + file_hashes = hash_manager.hexdigest() |
138 | 187 |
|
139 |
| - md5_digest = md5_hash.hexdigest() |
140 |
| - sha2_digest = sha256_hash.hexdigest() |
141 |
| - blake2_256_digest = blake2_256_hash.hexdigest() |
| 188 | + md5_digest = file_hashes.md5 |
| 189 | + sha2_digest = file_hashes.sha256 |
| 190 | + blake2_256_digest = file_hashes.blake2_256 |
142 | 191 |
|
143 | 192 | py_version: str | None = None
|
144 | 193 | if file_type == "bdist_wheel":
|
|
0 commit comments