bpo-45150: Add hashlib.file_digest() for efficient file hashing (GH-3… · python/cpython@4f97d64 (original) (raw)

`@@ -10,6 +10,7 @@

`

10

10

`from binascii import unhexlify

`

11

11

`import hashlib

`

12

12

`import importlib

`

``

13

`+

import io

`

13

14

`import itertools

`

14

15

`import os

`

15

16

`import sys

`

`@@ -20,6 +21,7 @@

`

20

21

`from test import support

`

21

22

`from test.support import _4G, bigmemtest

`

22

23

`from test.support.import_helper import import_fresh_module

`

``

24

`+

from test.support import os_helper

`

23

25

`from test.support import threading_helper

`

24

26

`from test.support import warnings_helper

`

25

27

`from http.client import HTTPException

`

`@@ -371,6 +373,31 @@ def check(self, name, data, hexdigest, shake=False, **kwargs):

`

371

373

`if not shake:

`

372

374

`self.assertEqual(len(digest), m.digest_size)

`

373

375

``

``

376

`+

if not shake and kwargs.get("key") is None:

`

``

377

`+

skip shake and blake2 extended parameter tests

`

``

378

`+

self.check_file_digest(name, data, hexdigest)

`

``

379

+

``

380

`+

def check_file_digest(self, name, data, hexdigest):

`

``

381

`+

hexdigest = hexdigest.lower()

`

``

382

`+

digests = [name]

`

``

383

`+

digests.extend(self.constructors_to_test[name])

`

``

384

+

``

385

`+

with open(os_helper.TESTFN, "wb") as f:

`

``

386

`+

f.write(data)

`

``

387

+

``

388

`+

try:

`

``

389

`+

for digest in digests:

`

``

390

`+

buf = io.BytesIO(data)

`

``

391

`+

buf.seek(0)

`

``

392

`+

self.assertEqual(

`

``

393

`+

hashlib.file_digest(buf, digest).hexdigest(), hexdigest

`

``

394

`+

)

`

``

395

`+

with open(os_helper.TESTFN, "rb") as f:

`

``

396

`+

digestobj = hashlib.file_digest(f, digest)

`

``

397

`+

self.assertEqual(digestobj.hexdigest(), hexdigest)

`

``

398

`+

finally:

`

``

399

`+

os.unlink(os_helper.TESTFN)

`

``

400

+

374

401

`def check_no_unicode(self, algorithm_name):

`

375

402

`# Unicode objects are not allowed as input.

`

376

403

`constructors = self.constructors_to_test[algorithm_name]

`

`@@ -1117,6 +1144,33 @@ def test_normalized_name(self):

`

1117

1144

`self.assertNotIn("blake2b512", hashlib.algorithms_available)

`

1118

1145

`self.assertNotIn("sha3-512", hashlib.algorithms_available)

`

1119

1146

``

``

1147

`+

def test_file_digest(self):

`

``

1148

`+

data = b'a' * 65536

`

``

1149

`+

d1 = hashlib.sha256()

`

``

1150

`+

self.addCleanup(os.unlink, os_helper.TESTFN)

`

``

1151

`+

with open(os_helper.TESTFN, "wb") as f:

`

``

1152

`+

for _ in range(10):

`

``

1153

`+

d1.update(data)

`

``

1154

`+

f.write(data)

`

``

1155

+

``

1156

`+

with open(os_helper.TESTFN, "rb") as f:

`

``

1157

`+

d2 = hashlib.file_digest(f, hashlib.sha256)

`

``

1158

+

``

1159

`+

self.assertEqual(d1.hexdigest(), d2.hexdigest())

`

``

1160

`+

self.assertEqual(d1.name, d2.name)

`

``

1161

`+

self.assertIs(type(d1), type(d2))

`

``

1162

+

``

1163

`+

with self.assertRaises(ValueError):

`

``

1164

`+

hashlib.file_digest(None, "sha256")

`

``

1165

+

``

1166

`+

with self.assertRaises(ValueError):

`

``

1167

`+

with open(os_helper.TESTFN, "r") as f:

`

``

1168

`+

hashlib.file_digest(f, "sha256")

`

``

1169

+

``

1170

`+

with self.assertRaises(ValueError):

`

``

1171

`+

with open(os_helper.TESTFN, "wb") as f:

`

``

1172

`+

hashlib.file_digest(f, "sha256")

`

``

1173

+

1120

1174

``

1121

1175

`if name == "main":

`

1122

1176

`unittest.main()

`